<?php
/*
 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
 * Copyright (C) 2002-2012 The Nucleus Group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * (see nucleus/documentation/index.html#license for more info)
 */
/**
 * The code for the Nucleus admin area
 *
 * @license http://nucleuscms.org/license.txt GNU General Public License
 * @copyright Copyright (C) 2002-2012 The Nucleus Group 
 * @version $Id: ADMIN.php 180 2012-02-27 00:37:33Z shizuki17xx $
 */

if ( !function_exists('requestVar') ) {
    exit;
}

function __autoload($className) {
    $classes = array(
        'skinableFACTORY',
        'skinableSKIN',
        'skinableTEMPLATE',
        'skinableACTIONS',
        'skinableSKINIMPORT',
        'skinableSKINEXPORT',
        'skinableENCAPSULATE',
        'skinableNAVLIST',
        'skinableBATCH',
    );
    if (in_array($className, $classes)) {
        if ($className == 'skinableSKINIMPORT' || $className == 'skinableSKINEXPORT') {
            $className = 'skinableSkinie';
        }
        if ($className == 'skinableNAVLIST' || $className == 'skinableBATCH') {
            $className = 'skinableENCAPSULATE';
        }
        global $DIR_LIBS;
        $filePath = $DIR_LIBS . 'skinableadmin/' . $className . '.php';
        if (file_exists($filePath)) {
            include_once($filePath);
        }
    }
}

require_once $DIR_LIBS . '/skinableadmin/skinableShowlist.php';

/**
 * Builds the admin area and executes admin actions
 */
class ADMIN
{

    /**
     * @var string $action action currently being executed ($action=xxxx -> action_xxxx method)
     */
    public $action;

    /**
     * @var object $adminSkin
     */
    public $adminSkin;

    /**
     * @var string $extrahead
     */
    public $extrahead;

    /**
     * @var bool $passvar
     */
    public $passvar;

    /**
     * @var string $headMess
     */
    public $headMess;

    public $aOptions;

    /**
     * Class constructor
     */
    function __construct()
    {
        global $member, $DIR_LIBS;

        if (!defined('_SKINABLEADMIN_DEFINED_VARS'))
        {
            if ($member)
            {
                $locale = $member->getLocale();
                if (!$locale)
                {
                    $locale = i18n::get_current_locale();
                }
            }
            $translation_file = $DIR_LIBS . 'skinableadmin/locales/' . $locale . '.' . i18n::get_current_charset() . '.php';

            if (!file_exists($translation_file)) {
                $locale = 'en_Latn_US';
                $translation_file = $DIR_LIBS . 'skinableadmin/locales/en_Latn_US.ISO-8859-1.php';
            }
            include($translation_file);
        }

        $query = 'SELECT '
               . '    COUNT(*) as result '
               . 'FROM '
               .      sql_table('adminskin_desc');
        if (!(quickQuery($query))) {
            $this->action_importAdmin();
        }
        if (!isset($adminSkinid) || !($adminSkinid)) {
            $adminSkinid = self::getAdminSkinID();
        }
        if (skinableSKIN::existsID($adminSkinid)) {
            $this->adminSkin = new skinableSKIN($adminSkinid);
        } else {
            $this->adminSkin = 0;
        }
    }

    static private function getAdminSkinID()
    {
        global $CONF, $member, $manager;
        if (isset($member) && $member->isLoggedIn()) {
            $memskin = $member->getAdminSkin();
            if ($memskin) {
                return $memskin;
            }
        }
        return $CONF['DefaultAdminSkin'];
    }

    function getAdminskinEditActions()
    {
        return array(
            'adminskinoverview',
            'adminskinieoverview',
            'adminskinedittype',
            'adminskinremovetype',
            'adminskindelete',
            'adminskinedit',
            'adminskinieimport',
            'adminskiniedoimport',
            'admintemplateedit',
            'admintemplateoverview',
            'admintemplatedelete',
        );
    }

    function getSkinlessActions()
    {
        return array(
            'plugindeleteconfirm',
            'pluginoptionsupdate',
            'skinremovetypeconfirm',
            'skinclone',
            'skindeleteconfirm',
            'skinnew',
            'skineditgeneral',
            'skinieexport',
            'skinupdate',
            'templateupdate',
            'templatedeleteconfirm',
            'templatenew',
            'templateclone',
            'adminskinremovetypeconfirm',
            'adminskinclone',
            'adminskindeleteconfirm',
            'adminskinnew',
            'adminskineditgeneral',
            'adminskinieexport',
            'adminskinupdate',
            'admintemplateupdate',
            'admintemplatedeleteconfirm',
            'admintemplatenew',
            'admintemplateclone',
            'blogsettingsupdate',
            'settingsupdate',
            'addnewlog2',
            'additem',
            'itemdeleteconfirm',
            'itemupdate',
            'changemembersettings',
            'clearactionlog',
            'memberedit',
        );
    }

    /**
     * Executes an action
     *
     * @param string $action action to be performed
     */
    function action($action)
    {
        global $CONF, $manager;
        $f = false;
        // list of action aliases
        $alias = array(
            'login' => 'overview',
            ''      => 'overview'
        );
        $customAction = postvar('customaction');
        if (!empty($customAction)) {
            $alias = array(
                'login' => $customAction,
                ''      => $customAction
            );
        }
        if (isset($alias[$action])) {
            $action = $alias[$action];
        }
        $methodName   = 'action_' . $action;
        $this->action = strtolower($action);
        // check ticket. All actions need a ticket, unless they are considered to be safe (a safe action
        // is an action that requires user interaction before something is actually done)
        // all safe actions are in this array:
        $actionsNotToCheck = array(
            'showlogin',
            'login',
            'overview',
            'itemlist',
            'blogcommentlist',
            'bookmarklet',
            'blogsettings',
            'banlist',
            'deleteblog',
            'editmembersettings',
            'browseownitems',
            'browseowncomments',
            'createitem',
            'itemedit',
            'itemmove',
            'categoryedit',
            'categorydelete',
            'manage',
            'actionlog',
            'settingsedit',
            'backupoverview',
            'pluginlist',
            'createnewlog',
            'usermanagement',
            'skinoverview',
            'templateoverview',
            'skinieoverview',
            'itemcommentlist',
            'commentedit',
            'commentdelete',
            'banlistnewfromitem',
            'banlistdelete',
            'itemdelete',
            'manageteam',
            'teamdelete',
            'banlistnew',
            'memberedit',
            'memberdelete',
            'pluginhelp',
            'pluginoptions',
            'plugindelete',
            'skinedittype',
            'skinremovetype',
            'skindelete',
            'skinedit',
            'templateedit',
            'templatedelete',
            'activate',
            'systemoverview',
            'activatesetpwd',
        );
        $synonimActions = array(
            'banlistnewfromitem',
            'memberedit',
            'login',
        );
        $adminskinEditActions = $this->getAdminskinEditActions();
        $skinLessActions      = $this->getSkinlessActions();
        $allowActions         = array_merge($synonimActions, $this->getSkinlessActions());
        $actionsNotToCheck = array_merge($actionsNotToCheck, $adminskinEditActions, $allowActions);
        if (!in_array($this->action, $actionsNotToCheck) && !$this->existsSkinContents($action)) {
            if (!$manager->checkTicket()) {
                $this->error(_ERROR_BADTICKET);
            }
        }
        if ($this->adminSkin) {
            if ($this->existsSkinContents($action) || in_array($this->action, $allowActions)) {
                $adminClass =& $this;
            } elseif ($CONF['DefaultAdminSkin']) {
                $this->adminSkin = new skinableSKIN($CONF['DefaultAdminSkin']);
            }
        } elseif ($CONF['DefaultAdminSkin']) {
            $this->adminSkin = new skinableSKIN($CONF['DefaultAdminSkin']);
        }
        if (!method_exists($this, $methodName) && !in_array($this->action, $allowActions) && $this->existsSkinContents($action)) {
            $this->action_parseSpecialskin;
            $f = true;
        } elseif (method_exists($this, $methodName)) {
            call_user_func(array(&$this, $methodName));
            $f = true;
        }
        if ($f) {
            exit;
        }
            $id              = self::getAdminSkinID();
            $this->adminSkin = new skinableSKIN($id);
            if ($this->adminSkin && $this->existsSkinContents('adminerrorpage')) {
                $this->error(_BADACTION . ENTITY::hsc($action, ENT_QUOTES));
                $f = true;
            } elseif ($id != $CONF['DefaultAdminSkin']) {
                $this->adminSkin = new skinableSKIN($CONF['DefaultAdminSkin']);
                if ($this->adminSkin && $this->existsSkinContents('adminerrorpage')) {
                    $this->error(_BADACTION . ENTITY::hsc($action, ENT_QUOTES));
                    $f = true;
                }
            }
        if ($f) {
            exit;
        }
        $adminClass = new baseADMIN;
        $adminClass->error(_BADACTION . ENTITY::hsc($action, ENT_QUOTES));
    }

    /**
     * Check skin contents
     *
     * @param str
     * @return bool
     */
    function existsSkinContents($action)
    {
        $nsActions = $this->getSkinlessActions();
        $in_array  = in_array($action, $nsActions);
        if ($in_array) {
            return $in_array;
        } else {
            $query = 'SELECT '
                   . '    scontent as result '
                   . 'FROM '
                   .      sql_table('adminskin') . ' '
                   . 'WHERE '
                   . '    sdesc = %d '
                   . 'AND stype = "%s"';
            if (is_object($this->adminSkin)) {
                return quickQuery(sprintf($query, $this->adminSkin->id, sql_real_escape_string($action)));
            } else {
                return quickQuery(sprintf($query, 1, sql_real_escape_string($action)));
            }
        }
    }

    /**
     * Check exists specialskinparts
     *
     * @param string action type
     * @return bool
     */
    function specialActionsAllow($action)
    {
        $query = 'SELECT '
               . '    sdesc as result '
               . 'FROM '
               .      sql_table('adminskin') . ' '
               . 'WHERE '
               . '    sdesc = %d '
               . 'AND stype = "%s"';
        return quickQuery(sprintf($query, $this->adminSkin->id, sql_real_escape_string($action)));
    }

    /**
     * @todo document this
     */
    function action_showlogin()
    {
        global $error;
        $this->action_login($error);
    }

    /**
     * @todo document this
     */
    function action_login($msg = '', $passvars = 1)
    {
        global $member;
        // skip to overview when allowed
        if ($member->isLoggedIn() && $member->canLogin()) {
            $this->action_overview();
            exit;
        }
        $this->passvar = $passvars;
        if ($msg) {
            $this->headMess = $msg;
        }
        $this->pagehead();
        $this->parse('showlogin');
        $this->pagefoot();
    }

    /**
     * provides a screen with the overview of the actions available
     * @todo document parameter
     */
    function action_overview($msg = '')
    {
        if ($msg) {
            $this->headMess = $msg;
        }
        $this->pagehead();
        $this->parse('overview');
        $this->pagefoot();
    }

    /**
     * Returns a link to a weblog
     * @param object BLOG
     *
    function bloglink(&$blog) {
        return '<a href="'.ENTITY::hsc($blog->getURL()).'" title="'._BLOGLIST_TT_VISIT.'">'. ENTITY::hsc( $blog->getName() ) .'</a>';
    }

    /**
     * @todo document this
     */
    function action_manage($msg = '')
    {
        global $member;
        if ($msg) {
            $this->headMess = $msg;
        }
        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('manage');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_itemlist($blogid = '')
    {
        global $member, $manager, $CONF;
        if ($blogid == '') {
            $blogid = intRequestVar('blogid');
        } elseif (!empty($blogid)) {
            $_REQUEST['blogid'] = $_GET['blogid'] = $_POST['blogid'] = $blogid;
        }
        $member->teamRights($blogid) or $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('itemlist');
        $this->pagefoot();
    }

    /**
     * Batch actions
     *
     * @param string action type
     */
    private function _batchActions($actionType)
    {
        global $member, $manager;

        // check if logged in
        $member->isLoggedIn() or $this->disallow();

        if ($actionType == 'team') {
            $blogid = intRequestVar('blogid');
            // check if blog admin rights
            $member->blogAdminRights($blogid) or $this->disallow();
        }

        if ($actionType == 'member') {
            // check if admin
            $member->isAdmin() or $this->disallow();
        }

        // get array of itemids from request
        $selected = requestIntArray('batch');
        $action   = requestVar('batchaction');

        // Show error when no items were selected
        if (!is_array($selected) || sizeof($selected) == 0) {
            $this->error(_BATCH_NOSELECTION);
        }

        // On move: when no destination blog/category chosen, show choice now
        if ($action == 'move') {
            switch ($actionType) {
                case 'item':
                    $destId = intRequestVar('destcatid');
                    $exFunc = 'existsCategory';
                    break;
                case 'category':
                    $destId = intRequestVar('destblogid');
                    $exFunc = 'existsBlogID';
                    break;
            }
            if (!$manager->$exFunc($destId)) {
                $this->batchMoveSelectDestination($actionType, $selected);
            }
        }

        // On delete: check if confirmation has been given
        if (($action == 'delete') && (requestVar('confirmation') != 'yes')) {
            $this->batchAskDeleteConfirmation($actionType, $selected);
        }

        // Output via skins
        $this->pagehead();
        $this->parse('batch' . $actionType);
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_batchitem()
    {
        $this->_batchActions('item');
    }

    /**
     * @todo document this
     */
    function action_batchcomment()
    {
        $this->_batchActions('comment');
    }

    /**
     * @todo document this
     */
    function action_batchmember()
    {
        $this->_batchActions('member');
    }

    /**
     * @todo document this
     */
    function action_batchteam()
    {
        $this->_batchActions('team');
    }

    /**
     * @todo document this
     */
    function action_batchcategory()
    {
        $this->_batchActions('category');
    }

    /**
     * @todo document this
     */
    function batchMoveSelectDestination($type, $ids)
    {
        $this->pagehead();
        $this->parse('batchmove');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function batchAskDeleteConfirmation($type, $ids)
    {
        $this->pagehead();
        $this->parse('batchdelete');
        $this->pagefoot();
    }


    /**
     * Inserts a HTML select element with choices for all categories to which the current
     * member has access
     * @see function selectBlog
     */
    function selectBlogCategory($name, $selected = 0, $tabindex = 0, $showNewCat = 0, $iForcedBlogInclude = -1)
    {
        self::selectBlog($name, 'category', $selected, $tabindex, $showNewCat, $iForcedBlogInclude);
    }

    /**
     * Inserts a HTML select element with choices for all blogs to which the user has access
     *      mode = 'blog' => shows blognames and values are blogids
     *      mode = 'category' => show category names and values are catids
     *
     * @param $iForcedBlogInclude
     *      ID of a blog that always needs to be included, without checking if the
     *      member is on the blog team (-1 = none)
     * @todo document parameters
     */
    function selectBlog($name, $mode='blog', $selected = 0, $tabindex = 0, $showNewCat = 0, $iForcedBlogInclude = -1)
    {
        global $member, $CONF;

        // 0. get IDs of blogs to which member can post items (+ forced blog)
        $aBlogIds = array();
        if ($iForcedBlogInclude != -1)
            $aBlogIds[] = intval($iForcedBlogInclude);

        if (($member->isAdmin()) && (isset($CONF['ShowAllBlogs']) && !empty($CONF['ShowAllBlogs']))) {
            $queryBlogs = 'SELECT bnumber FROM ' . sql_table('blog') . ' ORDER BY bname';
        } else {
            $queryBlogs = 'SELECT bnumber FROM ' . sql_table('blog') . ', ' . sql_table('team')
                        . ' WHERE tblog=bnumber and tmember=' . $member->getID();
        }
        $rblogids = sql_query($queryBlogs);
        while ($o = sql_fetch_object($rblogids)) {
            if ($o->bnumber != $iForcedBlogInclude) {
                $aBlogIds[] = intval($o->bnumber);
            }
        }

        if (count($aBlogIds) == 0) {
            return;
        }

        $_REQUEST['selectData'] = array(
            'name'       => $name,
            'tabindex'   => $tabindex,
            'mode'       => $mode,
            'selected'   => $selected,
            'showNewCat' => $showNewCat,
            'aBlogIds'   => $aBlogIds,
        );
        $this->parse('blogselectbox');
    }

    /**
     * @todo document this
     */
    function action_browseownitems()
    {
        global $member, $manager, $CONF;

        $this->pagehead();
        $this->parse('browseownitems');
        $this->pagefoot();
    }

    /**
     * Show all the comments for a given item
     * @param int $itemid
     */
    function action_itemcommentlist($itemid = '')
    {
        global $member, $manager, $CONF;

        if ($itemid == '') {
            $itemid = intRequestVar('itemid');
        }
        $_REQUEST['itemid'] = $itemid;
        $_REQUEST['blogid'] = getBlogIdFromItemId($itemid);

        // only allow if user is allowed to alter item
        $member->canAlterItem($itemid) or $this->disallow();

        $blogid = getBlogIdFromItemId($itemid);

        $this->pagehead();
        $this->parse('itemcommentlist');
        $this->pagefoot();
    }

    /**
     * Browse own comments
     */
    function action_browseowncomments()
    {
        $this->pagehead();
        $this->parse('browseowncomments');
        $this->pagefoot();
    }

    /**
     * Browse all comments for a weblog
     * @param int $blogid
     */
    function action_blogcommentlist($blogid = '')
    {
        global $member, $manager, $CONF;

        if ($blogid == '') {
            $blogid = intRequestVar('blogid');
        } else {
            $blogid = intval($blogid);
        }

        $member->teamRights($blogid) or $member->isAdmin() or $this->disallow();

        $_REQUEST['blogid'] = $blogid;

        $this->pagehead();
        $this->parse('blogcommentlist');
        $this->pagefoot();
    }

    /**
     * Provide a page to item a new item to the given blog
     */
    function action_createitem()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        // check if allowed
        $member->teamRights($blogid) or $this->disallow();
        $memberid =  $member->getID();
        $blog     =& $manager->getBlog($blogid);
        $this->pagehead();
        $this->parse('createitem');

        // generate the add-item form
//        $formfactory = new PAGEFACTORY($blogid);
//        $formfactory->createAddForm('admin');

        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_itemedit()
    {
        global $member, $manager;
        $itemid = intRequestVar('itemid');
        // only allow if user is allowed to alter item
        $member->canAlterItem($itemid) or $this->disallow();
        $item =& $manager->getItem($itemid, 1, 1);
        $blog =& $manager->getBlog(getBlogIDFromItemID($itemid));
/*
        $manager->notify(
            'PrepareItemForEdit',
            array(
                'item' => &$item
            )
        );

        if ($blog->convertBreaks()) {
            $item['body'] = removeBreaks($item['body']);
            $item['more'] = removeBreaks($item['more']);
        }
*/
        // form to edit blog items
        $this->pagehead();
        $this->parse('itemedit');
//        $formfactory = new PAGEFACTORY($blog->getID());
//        $formfactory->createEditForm('admin',$item);
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_itemupdate()
    {
        global $member, $manager, $CONF;

        $itemid = intRequestVar('itemid');
        $catid  = postVar('catid');

        // only allow if user is allowed to alter item
        $member->canUpdateItem($itemid, $catid) or $this->disallow();

        $actiontype = postVar('actiontype');

        // delete actions are handled by itemdelete (which has confirmation)
        if ($actiontype == 'delete') {
            $this->action_itemdelete();
            return;
        }

        $body    = postVar('body');
        $title   = postVar('title');
        $more    = postVar('more');
        $closed  = intPostVar('closed');
        $draftid = intPostVar('draftid');

        // default action = add now
        if (!$actiontype)
            $actiontype='addnow';

        // create new category if needed
        if (strstr($catid,'newcat')) {
            // get blogid
            list($blogid) = sscanf($catid,"newcat-%d");

            // create
            $blog =& $manager->getBlog($blogid);
            $catid = $blog->createNewCategory();

            // show error when sth goes wrong
            if (!$catid) {
                $this->doError(_ERROR_CATCREATEFAIL);
            }
        }

        /*
            set some variables based on actiontype

            actiontypes:
                draft items -> addnow, addfuture, adddraft, delete
                non-draft items -> edit, changedate, delete

            variables set:
                $timestamp: set to a nonzero value for future dates or date changes
                $wasdraft: set to 1 when the item used to be a draft item
                $publish: set to 1 when the edited item is not a draft
        */
        $blogid =  getBlogIDFromItemID($itemid);
        $blog   =& $manager->getBlog($blogid);

        $wasdrafts = array('adddraft', 'addfuture', 'addnow');
        $wasdraft  = in_array($actiontype, $wasdrafts) ? 1 : 0;
        $publish   = ($actiontype != 'adddraft' && $actiontype != 'backtodrafts') ? 1 : 0;
        if ($actiontype == 'addfuture' || $actiontype == 'changedate') {
            $timestamp = mktime(intPostVar('hour'), intPostVar('minutes'), 0, intPostVar('month'), intPostVar('day'), intPostVar('year'));
        } else {
            $timestamp =0;
        }

        // edit the item for real
        ITEM::update($itemid, $catid, $title, $body, $more, $closed, $wasdraft, $publish, $timestamp);

        $this->updateFuturePosted($blogid);

        if ($draftid > 0) {
            // delete permission is checked inside ITEM::delete()
            ITEM::delete($draftid);
        }

        // show category edit window when we created a new category
        // ($catid will then be a new category ID, while postVar('catid') will be 'newcat-x')
        if ($catid != intPostVar('catid')) {
            $this->action_categoryedit(
                $catid,
                $blog->getID(),
                $CONF['AdminURL'] . 'index.php?action=itemlist&blogid=' . getBlogIDFromItemID($itemid)
            );
        } else {
            $item = ITEM::getItem($itemid, 0, 0);
            $cnt  = quickQuery('SELECT COUNT(*) FROM ' . sql_table('item') . ' WHERE unix_timestamp(itime) <= ' . $item['timestamp']);

            $_REQUEST['start'] = $cnt + 1;

            $this->action_itemlist(getBlogIDFromItemID($itemid));
        }
    }

    /**
     * @todo document this
     */
    function action_itemdelete()
    {
        global $member, $manager;

        $itemid = intRequestVar('itemid');

        // only allow if user is allowed to alter item
        $member->canAlterItem($itemid) or $this->disallow();

        if (!$manager->existsItem($itemid, 1, 1)) {
            $this->error(_ERROR_NOSUCHITEM);
        }

        $this->pagehead();
        $this->parse('itemdelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_itemdeleteconfirm()
    {
        global $member;

        $itemid = intRequestVar('itemid');

        // only allow if user is allowed to alter item
        $member->canAlterItem($itemid) or $this->disallow();

        // get blogid first
        $blogid = getBlogIdFromItemId($itemid);

        // delete item (note: some checks will be performed twice)
        $this->deleteOneItem($itemid);

        $this->action_itemlist($blogid);
    }

    /**
     * Deletes one item and returns error if something goes wrong
     * @param int $itemid
     */
    function deleteOneItem($itemid)
    {
        global $member, $manager;

        // only allow if user is allowed to alter item (also checks if itemid exists)
        if (!$member->canAlterItem($itemid)) {
            return _ERROR_DISALLOWED;
        }

        // need to get blogid before the item is deleted
        $blogid = getBlogIDFromItemId($itemid);

        $manager->loadClass('ITEM');
        ITEM::delete($itemid);

        // update blog's futureposted
        $this->updateFuturePosted($blogid);
    }

    /**
     * ADMIN::updateFuturePosted()
     * Update a blog's future posted flag
     *
     * @param integer $blogid
     * @return	void
     *
     */
    function updateFuturePosted($blogid)
    {
        global $manager;
        $blogid      =  intval($blogid);
        $blog        =& $manager->getBlog($blogid);
        $currenttime =  $blog->getCorrectTime(time());

        $query       =  "SELECT * FROM %s WHERE iblog=%d AND iposted=0 AND itime>'%s'";
        $query       =  sprintf($query, sql_table('item'), $blogid, i18n::formatted_datetime('mysql', $currenttime));
        $result      = sql_query($query);

        if (sql_num_rows($result) > 0)
        {
            $blog->setFuturePost();
        }
        else
        {
            $blog->clearFuturePost();
        }
        return;
    }

    /**
     * @todo document this
     */
    function action_itemmove()
    {
        global $member, $manager;

        $itemid = intRequestVar('itemid');

        // only allow if user is allowed to alter item
        $member->canAlterItem($itemid) or $this->disallow();

        $this->pagehead();
        $this->parse('itemmove');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_itemmoveto()
    {
        global $member, $manager;

        $itemid = intRequestVar('itemid');
        $catid  = requestVar('catid');

        // create new category if needed
        if (strstr($catid,'newcat')) {
            // get blogid
            list($blogid) = sscanf($catid,'newcat-%d');

            // create
            $blog  =& $manager->getBlog($blogid);
            $catid =  $blog->createNewCategory();

            // show error when sth goes wrong
            if (!$catid) {
                $this->doError(_ERROR_CATCREATEFAIL);
            }
        }

        // only allow if user is allowed to alter item
        $member->canUpdateItem($itemid, $catid) or $this->disallow();

        $old_blogid = getBlogIDFromItemId($itemid);

        ITEM::move($itemid, $catid);

        // set the futurePosted flag on the blog
        $this->updateFuturePosted(getBlogIDFromItemId($itemid));

        // reset the futurePosted in case the item is moved from one blog to another
        $this->updateFuturePosted($old_blogid);

        if ($catid != intRequestVar('catid')) {
            $this->action_categoryedit($catid, $blog->getID());
        } else {
            $this->action_itemlist(getBlogIDFromCatID($catid));
        }
    }

    /**
     * Moves one item to a given category (category existance should be checked by caller)
     * errors are returned
     * @param int $itemid
     * @param int $destCatid category ID to which the item will be moved
     */
    function moveOneItem($itemid, $destCatid)
    {
        global $member;

        // only allow if user is allowed to move item
        if (!$member->canUpdateItem($itemid, $destCatid)) {
            return _ERROR_DISALLOWED;
        }

        ITEM::move($itemid, $destCatid);
    }

    /**
     * Adds a item to the chosen blog
     */
    function action_additem()
    {
        global $manager, $CONF;

        $manager->loadClass('ITEM');

        $result = ITEM::createFromRequest();

        if ($result['status'] == 'error') {
            $this->error($result['message']);
        }

        $blogid     =  getBlogIDFromItemID($result['itemid']);
        $blog       =& $manager->getBlog($blogid);
        $btimestamp =  $blog->getCorrectTime();
        $item       =  $manager->getItem(intval($result['itemid']), 1, 1);

        if ($result['status'] == 'newcategory') {
            $distURI = $manager->addTicketToUrl($CONF['AdminURL'] . 'index.php?action=itemList&blogid=' . intval($blogid));
            $this->action_categoryedit($result['catid'], $blogid, $distURI);
        } else {
//            $methodName = 'action_itemList';
//            call_user_func(array(&$this, $methodName), $blogid);
            $this->action_itemList($blogid);
        }
    }

    /**
     * Allows to edit previously made comments
     */
    function action_commentedit()
    {
        global $member, $manager;

        $commentid = intRequestVar('commentid');

        $member->canAlterComment($commentid) or $this->disallow();

        $this->pagehead();
        $this->parse('commentedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_commentupdate()
    {
        global $member, $manager;
        $commentid = intRequestVar('commentid');

        $member->canAlterComment($commentid) or $this->disallow();

        $url   = postVar('url');
        $email = postVar('email');
        $body  = postVar('body');

        // intercept words that are too long
        if (preg_match("@[a-zA-Z0-9|\.,;:!\?=\/\\]{90,90}@", $body) != false) {
            $this->error(_ERROR_COMMENT_LONGWORD);
        }

        // check length
        if (strlen($body) < 3) {
            $this->error(_ERROR_COMMENT_NOCOMMENT);
        }
        if (strlen($body) > 5000) {
            $this->error(_ERROR_COMMENT_TOOLONG);
        }


        // prepare body
        $body = COMMENT::prepareBody($body);

        // call plugins
        $manager->notify(
            'PreUpdateComment',
            array(
                'body' => &$body
            )
        );

        $query = 'UPDATE '
               .      sql_table('comment') . ' '
               . 'SET '
               . "    cmail   =  '" . sql_real_escape_string($url) . "', "
               . "    cemail  =  '" . sql_real_escape_string($email) . "', "
               . "    cbody   =  '" . sql_real_escape_string($body) . "' "
               . " WHERE "
               . "    cnumber =   " . $commentid;
        sql_query($query);

        // get itemid
        $res    = sql_query('SELECT citem FROM ' . sql_table('comment') . ' WHERE cnumber = ' . $commentid);
        $o      = sql_fetch_object($res);
        $itemid = $o->citem;

        if ($member->canAlterItem($itemid)) {
            $this->action_itemcommentlist($itemid);
        } else {
            $this->action_browseowncomments();
        }

    }

    /**
     * @todo document this
     */
    function action_commentdelete()
    {
        global $member, $manager;

        $commentid = intRequestVar('commentid');

        $member->canAlterComment($commentid) or $this->disallow();

        $this->pagehead();
        $this->parse('commentdelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_commentdeleteconfirm()
    {
        global $member;

        $commentid = intRequestVar('commentid');

        // get item id first
        $res    = sql_query('SELECT citem FROM '.sql_table('comment') .' WHERE cnumber=' . $commentid);
        $o      = sql_fetch_object($res);
        $itemid = $o->citem;

        $error  = $this->deleteOneComment($commentid);
        if ($error) {
            $this->doError($error);
        }

        if ($member->canAlterItem($itemid)) {
            $this->action_itemcommentlist($itemid);
        } else {
            $this->action_browseowncomments();
        }
    }

    /**
     * @todo document this
     */
    function deleteOneComment($commentid)
    {
        global $member, $manager;
        $commentid = intval($commentid);

        if (!$member->canAlterComment($commentid)) {
            return _ERROR_DISALLOWED;
        }

        $manager->notify(
            'PreDeleteComment',
            array(
                'commentid' => $commentid
            )
        );

        // delete the comments associated with the item
        $query = 'DELETE FROM ' . sql_table('comment') . ' WHERE cnumber = ' . $commentid;
        sql_query($query);

        $manager->notify(
            'PostDeleteComment',
            array(
                'commentid' => $commentid
            )
        );

        return '';
    }

    /**
     * Usermanagement main
     */
    function action_usermanagement()
    {
        global $member, $manager;

        // check if allowed
        $member->isAdmin() or $this->disallow();

        $this->pagehead();
        $this->parse('usermanagement');
        $this->pagefoot();
    }

    /**
     * Edit member settings
     */
    function action_memberedit() {
        $this->action_editmembersettings(intRequestVar('memberid'));
    }

    /**
     * @todo document this
     */
    function action_editmembersettings($memberid = '') {
        global $member, $manager, $CONF;

        if ($memberid == '') {
            $memberid = $member->getID();
        }
        $_REQUEST['memberid'] = $memberid;

        // check if allowed
        ($member->getID() == $memberid) or $member->isAdmin() or $this->disallow();

        $extrahead = '<script type="text/javascript" src="javascript/numbercheck.js"></script>';
        $this->pagehead($extrahead);
        $this->parse('editmembersettings');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_changemembersettings()
    {
        global $member, $CONF, $manager;

        $memberid = intRequestVar('memberid');

        // check if allowed
        ($member->getID() == $memberid) or $member->isAdmin() or $this->disallow();

        $name           = trim(strip_tags(postVar('name')));
        $realname       = trim(strip_tags(postVar('realname')));
        $password       = postVar('password');
        $repeatpassword = postVar('repeatpassword');
        $email          = strip_tags(postVar('email'));
        $url            = strip_tags(postVar('url'));
        $adminskin      = intPostVar('adminskin');

        # replaced eregi() below with preg_match(). ereg* functions are deprecated in PHP 5.3.0
        # original eregi: !eregi("^https?://", $url)

        // begin if: Sometimes user didn't prefix the URL with http:// or https://, this cause a malformed URL. Let's fix it.
        if (!preg_match("!^https?://!i", $url))
        {
            $url = 'http://' . $url;
        }

        $admin    = postVar('admin');
        $canlogin = postVar('canlogin');
        $notes    = strip_tags(postVar('notes'));
        $locale   = postVar('locale');

        $mem = MEMBER::createFromID($memberid);

        if ($CONF['AllowLoginEdit'] || $member->isAdmin()) {
            if (!isValidDisplayName($name)) {


                $this->error(_ERROR_BADNAME);
            }
            if (($name != $mem->getDisplayName()) && MEMBER::exists($name)) {
                $this->error(_ERROR_NICKNAMEINUSE);
            }
            if ($password != $repeatpassword) {
                $this->error(_ERROR_PASSWORDMISMATCH);
            }
            if ($password && (strlen($password) < 6)) {
                $this->error(_ERROR_PASSWORDTOOSHORT);
            }


            $pwdvalid = true;
            $pwderror = '';
            $manager->notify(
                'PrePasswordSet',
                array(
                    'password'     => $password,
                    'errormessage' => &$pwderror,
                    'valid'        => &$pwdvalid
                )
            );
            if (!$pwdvalid) {
                $this->error($pwderror);
            }
        }
        if (!isValidMailAddress($email)) {


            $this->error(_ERROR_BADMAILADDRESS);
        }
        if (!$realname) {

            $this->error(_ERROR_REALNAMEMISSING);
        }
        if (($locale != '') && (!in_array($locale, i18n::get_available_locale_list()))) {
            $this->error(_ERROR_NOSUCHLANGUAGE);
        }
        // check if there will remain at least one site member with both the logon and admin rights
        // (check occurs when taking away one of these rights from such a member)
        if (    (!$admin && $mem->isAdmin() && $mem->canLogin())
             || (!$canlogin && $mem->isAdmin() && $mem->canLogin())
           )
        {
            $q = 'SELECT '
               . '    * '
               . 'FROM '
               .      sql_table('member') . ' '
               . 'WHERE '
              . '    madmin    = 1 '
               . 'and mcanlogin = 1';
            $r = sql_query($q);
            if (sql_num_rows($r) < 2) {
                $this->error(_ERROR_ATLEASTONEADMIN);
            }
        }

        if ($CONF['AllowLoginEdit'] || $member->isAdmin()) {
            $mem->setDisplayName($name);
            if ($password) {
                $mem->setPassword($password);
            }
        }

        $oldEmail = $mem->getEmail();

        $mem->setRealName($realname);
        $mem->setEmail($email);
        $mem->setURL($url);
        $mem->setNotes($notes);
        $mem->setLocale($locale);
        $mem->setAdminSkin($adminskin);

        // only allow super-admins to make changes to the admin status
        if ($member->isAdmin()) {
            $mem->setAdmin($admin);
            $mem->setCanLogin($canlogin);
        }

        $autosave = postVar ('autosave');
        $mem->setAutosave($autosave);

        $mem->write();

        // store plugin options
        $aOptions = requestArray('plugoption');
        NucleusPlugin::apply_plugin_options($aOptions);
        $manager->notify(
            'PostPluginOptionsUpdate',
            array(
                'context'  => 'member',
                'memberid' => $memberid,
                'member'   => &$mem
            )
        );

        // if email changed, generate new password
        if ($oldEmail != $mem->getEmail())
        {
            $mem->sendActivationLink('addresschange', $oldEmail);
            // logout member
            $mem->newCookieKey();

            // only log out if the member being edited is the current member.
            if ($member->getID() == $memberid)
            {
                $member->logout();
            }
            $this->action_login(_MSG_ACTIVATION_SENT, 0);
            return;
        }


        if (  ($mem->getID() == $member->getID() )
           && ($mem->getDisplayName() != $member->getDisplayName() )
           ) 
        {
            $mem->newCookieKey();
            $member->logout();
            $this->action_login(_MSG_LOGINAGAIN, 0);
        } else {
            $this->action_overview(_MSG_SETTINGSCHANGED);
        }
    }

    /**
     * @todo document this
     */
    function action_memberadd()
    {
        global $member, $manager;

        // check if allowed
        $member->isAdmin() or $this->disallow();

        if (postVar('password') != postVar('repeatpassword')) {
            $this->error(_ERROR_PASSWORDMISMATCH);
        }
        if (strlen(postVar('password')) < 6) {
            $this->error(_ERROR_PASSWORDTOOSHORT);
        }

        $res = MEMBER::create(
            postVar('name'),
            postVar('realname'),
            postVar('password'),
            postVar('email'),
            postVar('url'),
            postVar('admin'),
            postVar('canlogin'),
            postVar('notes')
        );
        if ($res != 1) {
            $this->error($res);
        }

        // fire PostRegister event
        $newmem = new MEMBER();
        $newmem->readFromName(postVar('name'));
        $manager->notify(
            'PostRegister',
            array(
                'member' => &$newmem
            )
        );

        $this->action_usermanagement();
    }

    /**
     * Account activation
     *
     * @author dekarma
     */
    function action_activate()
    {

        $key = getVar('key');
        $this->_showActivationPage($key);
    }

    /**
     * @todo document this
     */
    function _showActivationPage($key, $message = '')
    {
        global $manager;

        // clean up old activation keys
        MEMBER::cleanupActivationTable();

        // get activation info
        $info = MEMBER::getActivationInfo($key);

        if (!$info) {
            $this->error(_ERROR_ACTIVATE);
        }

        $mem = MEMBER::createFromId($info->vmember);

        if (!$mem) {
            $this->error(_ERROR_ACTIVATE);
        }

        $_POST['ackey']        = $key;
        $this->headMess = $message;
        $_POST['bNeedsPasswordChange'] = true;
        $this->pagehead();
        $this->parse('activate');
        $this->pagefoot();
    }

    /**
     * Account activation - set password part
     *
     * @author dekarma
     */
    function action_activatesetpwd()
    {
        global $manager;
        $key = postVar('key');

        // clean up old activation keys
        MEMBER::cleanupActivationTable();

        // get activation info
        $info = MEMBER::getActivationInfo($key);

        if (!$info || ($info->type == 'addresschange')) {
            return $this->_showActivationPage($key, _ERROR_ACTIVATE);
        }
        $mem = MEMBER::createFromId($info->vmember);
        if (!$mem) {
            return $this->_showActivationPage($key, _ERROR_ACTIVATE);
        }

        $password       = postVar('password');
        $repeatpassword = postVar('repeatpassword');

        if ($password != $repeatpassword) {
            return $this->_showActivationPage($key, _ERROR_PASSWORDMISMATCH);
        }

        if ($password && (strlen($password) < 6)) {
            return $this->_showActivationPage($key, _ERROR_PASSWORDTOOSHORT);
        }

        $pwdvalid = true;
        $pwderror = '';
        $manager->notify(
            'PrePasswordSet',
            array(
                'password'     => $password,
                'errormessage' => &$pwderror,
                'valid'        => &$pwdvalid
            )
        );
        if (!$pwdvalid) {
            return $this->_showActivationPage($key,$pwderror);
        }

        $error = '';
        $manager->notify(
            'ValidateForm',
            array(
                'type'   => 'activation',
                'member' => $mem,
                'error'  => &$error
            )
        );
        if ($error != '')
            return $this->_showActivationPage($key, $error);


        // set password
        $mem->setPassword($password);
        $mem->write();

        // do the activation
        MEMBER::activate($key);

        $this->pagehead();
        $this->parse('activatesetpwd');
        $this->pagefoot();
    }

    /**
     * Manage team
     */
    function action_manageteam()
    {
        global $member, $manager, $blog;

        $blogid = intRequestVar('blogid');
        if (!$blog) {
            $blog =& $manager->getBlog($blogid);
        }

        // check if allowed
        $member->blogAdminRights($blogid) or $this->disallow();

        $this->pagehead();
        $this->parse('manageteam');
        $this->pagefoot();
    }

    /**
     * Add member to team
     */
    function action_teamaddmember()
    {
        global $member, $manager;

        $memberid = intPostVar('memberid');
        $blogid   = intPostVar('blogid');
        $admin    = intPostVar('admin');

        // check if allowed
        $member->blogAdminRights($blogid) or $this->disallow();

        $blog =& $manager->getBlog($blogid);
        if (!$blog->addTeamMember($memberid, $admin)) {
            $this->error(_ERROR_ALREADYONTEAM);
        }

        $this->action_manageteam();
    }

    /**
     * @todo document this
     */
    function action_teamdelete()
    {
        global $member, $manager;

        $memberid = intRequestVar('memberid');
        $blogid   = intRequestVar('blogid');

        // check if allowed
        $member->blogAdminRights($blogid) or $this->disallow();

        $teammem =  MEMBER::createFromID($memberid);
        $blog    =& $manager->getBlog($blogid);

        $this->pagehead();
        $this->parse('teamdelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_teamdeleteconfirm()
    {
        global $member;
        $memberid = intRequestVar('memberid');
        $blogid   = intRequestVar('blogid');

        $error = $this->deleteOneTeamMember($blogid, $memberid);
        if ($error) {
            $this->error($error);
        }
        $this->action_manageteam();
    }

    /**
     * @todo document this
     */
    function deleteOneTeamMember($blogid, $memberid)
    {
        global $member, $manager;
        $blogid   = intval($blogid);
        $memberid = intval($memberid);
        // check if allowed
        if (!$member->blogAdminRights($blogid)) {
            return _ERROR_DISALLOWED;
        }
        // check if: - there remains at least one blog admin
        //           - (there remains at least one team member)
        $tmem = MEMBER::createFromID($memberid);
        $manager->notify(
            'PreDeleteTeamMember',
            array(
                'member' => &$tmem,
                'blogid' => $blogid
            )
        );
        if ($tmem->isBlogAdmin($blogid)) {
            // check if there are more blog members left and at least one admin
            // (check for at least two admins before deletion)
            $query = 'SELECT '
                   . '    * '
                   . 'FROM '
                   .      sql_table('team') . ' '
                   . 'WHERE '
                   . '    tblog  = %d '
                   . 'and tadmin = 1';
            $r     = sql_query(sprintf($query, $blogid));
            if (sql_num_rows($r) < 2) {
                return _ERROR_ATLEASTONEBLOGADMIN;
            }
        }
        $query = 'DELETE '
               . 'FROM '
               .      sql_table('team') . ' '
               . 'WHERE '
               . '    tblog   = %d '
               . 'and tmember = %d';
        sql_query(sprintf($query, $blogid, $memberid));
        $manager->notify(
            'PostDeleteTeamMember',
            array(
                'member' => &$tmem,
                'blogid' => $blogid
            )
        );
        return '';
    }

    /**
     * @todo document this
     */
    function action_teamchangeadmin()
    {
        global $member;
        $blogid   = intRequestVar('blogid');
        $memberid = intRequestVar('memberid');
        // check if allowed
        $member->blogAdminRights($blogid) or $this->disallow();

        $mem = MEMBER::createFromID($memberid);
        // don't allow when there is only one admin at this moment
        if ($mem->isBlogAdmin($blogid)) {
            $q = 'SELECT '
               . '    * '
               . 'FROM '
               .      sql_table('team') . ' '
               . 'WHERE '
               . '    tblog  = %d '
               . 'and tadmin = 1';
            $r = sql_query(sprintf($q, $blogid));
            if (sql_num_rows($r) == 1) {
                $this->error(_ERROR_ATLEASTONEBLOGADMIN);
            }
        }

        if ($mem->isBlogAdmin($blogid)) {
            $newval = 0;
        } else {
            $newval = 1;
        }

        $query = 'UPDATE '
               .      sql_table('team') . ' '
               . 'SET '
               . '    tadmin = %d '
               . 'WHERE '
               . '    tblog   = %d '
               . 'and tmember = %d';
        sql_query(sprintf($query, $newval, $blogid, $memberid));

        // only show manageteam if member did not change its own admin privileges
        if ($member->isBlogAdmin($blogid)) {
            $this->action_manageteam();
        } else {
            $this->action_overview(_MSG_ADMINCHANGED);
        }
    }

    /**
     * @todo document this
     */
    function action_blogsettings()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        // check if allowed
        $member->blogAdminRights($blogid) or $this->disallow();
        $blog      =& $manager->getBlog($blogid);
        $extrahead =  '<script type="text/javascript" src="javascript/numbercheck.js"></script>';
        $this->pagehead($extrahead);
        $this->parse('blogsettings');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_categorynew()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $cname = postVar('cname');
        $cdesc = postVar('cdesc');
        if (!isValidCategoryName($cname)) {
            $this->error(_ERROR_BADCATEGORYNAME);
        }
        $query = 'SELECT '
               . '    * '
               . 'FROM '
               .      sql_table('category') . ' '
               . 'WHERE '
               . '    cname = "%s"'
               . 'AND cblog = %d';
        $res   = sql_query(sprintf($query, sql_real_escape_string($cname), intval($blogid)));
        if (sql_num_rows($res) > 0) {
            $this->error(_ERROR_DUPCATEGORYNAME);
        }
        $blog     =& $manager->getBlog($blogid);
        $newCatID =  $blog->createNewCategory($cname, $cdesc);
        $this->action_blogsettings();
    }

    /**
     * @todo document this
     */
    function action_categoryedit($catid = '', $blogid = '', $desturl = '')
    {
        global $member, $manager;
        if ($blogid == '') {
            $blogid = intGetVar('blogid');
        } else {
            $blogid = intval($blogid);
        }
        if ($catid == '') {
            $catid = intGetVar('catid');
        } else {
            $catid = intval($catid);
        }
        $_REQUEST['blogid']  = $blogid;
        $_REQUEST['catid']   = $catid;
        $_REQUEST['desturl'] = $desturl;
        $member->blogAdminRights($blogid) or $this->disallow();

        $extrahead = '<script type="text/javascript" src="javascript/numbercheck.js"></script>';
        $this->pagehead($extrahead);
        $this->parse('categoryedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_categoryupdate()
    {
        global $member, $manager;
        $blogid  = intPostVar('blogid');
        $catid   = intPostVar('catid');
        $cname   = postVar('cname');
        $cdesc   = postVar('cdesc');
        $desturl = postVar('desturl');

        $member->blogAdminRights($blogid) or $this->disallow();
        if (!isValidCategoryName($cname)) {
            $this->error(_ERROR_BADCATEGORYNAME);
        }
        $query = 'SELECT '
               . '    * '
               . 'FROM '
               .      sql_table('category') . ' '
               . 'WHERE '
               . '    cname = "%s" '
               . 'AND cblog = %d '
               . 'AND not(catid = %d)';
        $res   = sql_query(sprintf($query, sql_real_escape_string($cname), $blogid, $catid));
        if (sql_num_rows($res) > 0) {
            $this->error(_ERROR_DUPCATEGORYNAME);
        }
        $query = 'UPDATE '
               .      sql_table('category') . ' '
               . 'SET '
               . '    cname = "' . sql_real_escape_string($cname) . '", '
               . '    cdesc = "' . sql_real_escape_string($cdesc) . '" '
               . 'WHERE '
               . '    catid = ' . intval($catid);
        sql_query($query);
        // store plugin options
        $aOptions = requestArray('plugoption');
        NucleusPlugin::apply_plugin_options($aOptions);
        $manager->notify(
            'PostPluginOptionsUpdate',
            array(
                'context' => 'category',
                'catid'   => $catid
            )
        );
        if ($desturl) {
            redirect($desturl);
            exit;
        } else {
            $this->action_blogsettings();
        }
    }

    /**
     * @todo document this
     */
    function action_categorydelete()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        $catid  = intRequestVar('catid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $blog =& $manager->getBlog($blogid);
        // check if the category is valid
        if (!$blog->isValidCategory($catid)) {
            $this->error(_ERROR_NOSUCHCATEGORY);
        }
        // don't allow deletion of default category
        if ($blog->getDefaultCategory() == $catid) {
            $this->error(_ERROR_DELETEDEFCATEGORY);
        }
        // check if catid is the only category left for blogid
        $query = 'SELECT '
               . '    catid '
               . 'FROM '
               .      sql_table('category') . ' '
               . 'WHERE '
               . '    cblog = %d';
        $res   = sql_query(sprintf($query, $blogid));
        if (sql_num_rows($res) == 1) {
            $this->error(_ERROR_DELETELASTCATEGORY);
        }
        $this->pagehead();
        $this->parse('categorydelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_categorydeleteconfirm()
    {
        global $member, $manager;

        $blogid = intRequestVar('blogid');
        $catid  = intRequestVar('catid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $error = $this->deleteOneCategory($catid);
        if ($error) {
            $this->error($error);
        }
        $this->action_blogsettings();
    }

    /**
     * ADMIN::deleteOneCategory()
     * Delete a category by its id
     * 
     * @param	String	$catid	category id for deleting
     * @return	Void
     */
    function deleteOneCategory($catid)
    {
        global $manager, $member;
        $catid = intval($catid);
        $blogid = getBlogIDFromCatID($catid);
        if (!$member->blogAdminRights($blogid)) {
            return ERROR_DISALLOWED;
        }
        // get blog
        $blog =& $manager->getBlog($blogid);
        // check if the category is valid
        if (!$blog || !$blog->isValidCategory($catid)) {
            return _ERROR_NOSUCHCATEGORY;
        }
        $destcatid = $blog->getDefaultCategory();
        // don't allow deletion of default category
        if ($blog->getDefaultCategory() == $catid) {
            return _ERROR_DELETEDEFCATEGORY;
        }
        // check if catid is the only category left for blogid
        $query = 'SELECT '
               . '    catid '
               . 'FROM '
               .      sql_table('category') . ' '
               . 'WHERE '
               . '    cblog = %d';
        $res = sql_query(sprintf($query, $blogid));
        if (sql_num_rows($res) == 1) {
            return _ERROR_DELETELASTCATEGORY;
        }
        $manager->notify(
            'PreDeleteCategory',
            array(
                'catid' => $catid
            )
        );
        // change category for all items to the default category
        $query = 'UPDATE '
               .      sql_table('item') . ' '
               . 'SET '
               . '    icat = %d ' 
               . 'WHERE '
               . '    icat = %d';
        sql_query(sprintf($query, $destcatid, $catid));
        // delete all associated plugin options
        NucleusPlugin::delete_option_values('category', $catid);
        // delete category
        $query = 'DELETE '
               . 'FROM '
               .      sql_table('category') . ' '
               . 'WHERE '
               . '    catid = %d';
        sql_query(sprintf($query, $catid));
        $manager->notify(
            'PostDeleteCategory',
            array(
                'catid' => $catid
            )
        );
        return;

    }

    /**
     * @todo document this
     */
    function moveOneCategory($catid, $destblogid)
    {
        global $manager, $member;
        $catid      = intval($catid);
        $destblogid = intval($destblogid);
        $blogid     = getBlogIDFromCatID($catid);
        // mover should have admin rights on both blogs
        if (!$member->blogAdminRights($blogid)) {
            return _ERROR_DISALLOWED;
        }
        if (!$member->blogAdminRights($destblogid)) {
            return _ERROR_DISALLOWED;
        }
        // cannot move to self
        if ($blogid == $destblogid) {
            return _ERROR_MOVETOSELF;
        }
        // get blogs
        $blog     =& $manager->getBlog($blogid);
        $destblog =& $manager->getBlog($destblogid);
        // check if the category is valid
        if (!$blog || !$blog->isValidCategory($catid)) {
            return _ERROR_NOSUCHCATEGORY;
        }
        // don't allow default category to be moved
        if ($blog->getDefaultCategory() == $catid) {
            return _ERROR_MOVEDEFCATEGORY;
        }
        $manager->notify(
            'PreMoveCategory',
            array(
                'catid'      => &$catid,
                'sourceblog' => &$blog,
                'destblog'   => &$destblog
            )
        );
        // update comments table (cblog)
        $query = 'SELECT '
               . '    inumber '
               . 'FROM '
               .      sql_table('item') . ' '
               . 'WHERE '
               . '    icat = %d';
        $items = sql_query(sprintf($query, $catid));
        while ($oItem = sql_fetch_object($items)) {
            $query = 'UPDATE '
                   .      sql_table('comment') . ' '
                   . 'SET '
                   . '    cblog = %d' . ' '
                   . 'WHERE '
                   . '    citem = %d';
            sql_query(sprintf($query, $destblogid, $oItem->inumber));
        }

        // update items (iblog)
        $query = 'UPDATE '
               .      sql_table('item') . ' '
               . 'SET '
               . '    iblog = %d '
               . 'WHERE '
               . '    icat = %d';
        sql_query(sprintf($query, $destblogid, $catid));

        // move category
        $query = 'UPDATE '
               .      sql_table('comment') . ' '
               . 'SET '
               . '    cblog = %d' . ' '
               . 'WHERE '
               . '    catid = %d';
        sql_query(sprintf($query, $destblogid, $catid));
        $manager->notify(
            'PostMoveCategory',
            array(
                'catid'      => &$catid,
                'sourceblog' => &$blog,
                'destblog'   => $destblog
            )
        );

    }

    /**
     * ADMIN::action_blogsettingsupdate
     * Updating blog settings
     * 
     * @param	Void
     * @return	Void
     */
    function action_blogsettingsupdate()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $blog =& $manager->getBlog($blogid);
        $notify         = trim(postVar('notify'));
        $shortname      = trim(postVar('shortname'));
        $updatefile     = trim(postVar('update'));
        $notifyComment  = intPostVar('notifyComment');
        $notifyVote     = intPostVar('notifyVote');
        $notifyNewItem  = intPostVar('notifyNewItem');
        if ($notifyComment == 0) {
            $notifyComment = 1;
        }
        if ($notifyVote == 0) {
            $notifyVote = 1;
        }
        if ($notifyNewItem == 0) {
            $notifyNewItem = 1;
        }
        $notifyType = $notifyComment * $notifyVote * $notifyNewItem;
        if ($notify) {
            $not = new NOTIFICATION($notify);
            if (!$not->validAddresses()) {
                $this->error(_ERROR_BADNOTIFY);
            }
        }
        if (!isValidShortName($shortname)) {
            $this->error(_ERROR_BADSHORTBLOGNAME);
        }
        if (($blog->getShortName() != $shortname) && $manager->existsBlog($shortname)) {
            $this->error(_ERROR_DUPSHORTBLOGNAME);
        }
        // check if update file is writable
        if ($updatefile && !is_writeable($updatefile)) {
            $this->error(_ERROR_UPDATEFILE);
        }
        $blog->setName(trim(postVar('name')));
        $blog->setShortName($shortname);
        $blog->setNotifyAddress($notify);
        $blog->setNotifyType($notifyType);
        $blog->setMaxComments(postVar('maxcomments'));
        $blog->setCommentsEnabled(postVar('comments'));
        $blog->setTimeOffset(postVar('timeoffset'));
        $blog->setUpdateFile($updatefile);
        $blog->setURL(trim(postVar('url')));
        $blog->setDefaultSkin(intPostVar('defskin'));
        $blog->setDescription(trim(postVar('desc')));
        $blog->setPublic(postVar('public'));
        $blog->setConvertBreaks(intPostVar('convertbreaks'));
        $blog->setAllowPastPosting(intPostVar('allowpastposting'));
        $blog->setDefaultCategory(intPostVar('defcat'));
        $blog->setSearchable(intPostVar('searchable'));
        $blog->setEmailRequired(intPostVar('reqemail'));
        $blog->writeSettings();
        // store plugin options
        $aOptions = requestArray('plugoption');
        NucleusPlugin::apply_plugin_options($aOptions);
        $manager->notify(
            'PostPluginOptionsUpdate',
            array(
                'context' => 'blog',
                'blogid'  => $blogid,
                'blog'    => &$blog
            )
        );
        $this->action_overview(_MSG_SETTINGSCHANGED);
    }

    /**
     * @todo document this
     */
    function action_deleteblog()
    {
        global $member, $CONF, $manager;
        $blogid = intRequestVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();
        // check if blog is default blog
        if ($CONF['DefaultBlog'] == $blogid) {
            $this->error(_ERROR_DELDEFBLOG);
        }
        $blog =& $manager->getBlog($blogid);
        $this->pagehead();
        $this->parse('deleteblog');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_deleteblogconfirm()
    {
        global $member, $CONF, $manager;
        $blogid = intRequestVar('blogid');
        $manager->notify(
            'PreDeleteBlog',
            array(
                'blogid' => $blogid
            )
        );
        $member->blogAdminRights($blogid) or $this->disallow();
        // check if blog is default blog
        if ($CONF['DefaultBlog'] == $blogid) {
            $this->error(_ERROR_DELDEFBLOG);
        }
        $query = 'DELETE FROM %s WHERE %s = %d';
        // delete all comments
        sql_query(sprintf($query, sql_table('comment'), 'cblog', $blogid));
        // delete all items
        sql_query(sprintf($query, sql_table('item'), 'iblog', $blogid));
        // delete all team members
        sql_query(sprintf($query, sql_table('team'), 'tblog', $blogid));
        // delete all bans
        sql_query(sprintf($query, sql_table('ban'), 'blogid', $blogid));
        // delete all categories
        sql_query(sprintf($query, sql_table('category'), 'cblog', $blogid));
        // delete all associated plugin options
        NucleusPlugin::delete_option_values('blog', $blogid);
        // delete the blog itself
        sql_query(sprintf($query, sql_table('blog'), 'bnumber', $blogid));
        $manager->notify(
            'PostDeleteBlog',
            array(
                'blogid' => $blogid
            )
        );
        $this->action_overview(_DELETED_BLOG);
    }

    /**
     * @todo document this
     */
    function action_memberdelete()
    {
        global $member, $manager;
        $memberid = intRequestVar('memberid');
        ($member->getID() == $memberid) or $member->isAdmin() or $this->disallow();
        $mem = MEMBER::createFromID($memberid);
        $this->pagehead();
        $this->parse('memberdelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_memberdeleteconfirm()
    {
        global $member;
        $memberid = intRequestVar('memberid');
        ($member->getID() == $memberid) or $member->isAdmin() or $this->disallow();
        $error = $this->deleteOneMember($memberid);
        if ($error) {
            $this->error($error);
        }
        if ($member->isAdmin()) {
            $this->action_usermanagement(_DELETED_MEMBER);
        } else {
            $this->action_overview(_DELETED_MEMBER);
        }
    }

    /**
     * @static
     * @todo document this
     */
    function deleteOneMember($memberid)
    {
        global $manager;
        $memberid = intval($memberid);
        $member   = MEMBER::createFromID($memberid);
        if (!$member->canBeDeleted()) {
            return _ERROR_DELETEMEMBER;
        }
        $manager->notify(
            'PreDeleteMember',
            array(
                'member' => &$member
            )
        );
        /* unlink comments from memberid */
        if ($memberid) {
            $query = 'UPDATE '
                   .      sql_table('comment') . ' '
                   . 'SET '
                   . '    cmember = "0", '
                   . '    cuser   = "%s" '
                   . 'WHERE'
                   . '    cmember = %d'.$memberid;
            sql_query(sprintf($query, sql_real_escape_string($member->getDisplayName()), $memberid));
        }
        $query = 'DELETE FROM %s WHERE %s = ' . intval($memberid);
        sql_query(sprintf($query, sql_table('member'), 'mnumber'));
        sql_query(sprintf($query, sql_table('team'), 'tmember'));
        sql_query(sprintf($query, sql_table('activation'), 'vmember'));
        // delete all associated plugin options
        NucleusPlugin::delete_option_values('member', $memberid);
        $manager->notify(
            'PostDeleteMember',
            array(
                'member' => &$member
            )
        );
        return '';
    }

    /**
     * @todo document this
     */
    function action_createnewlog()
    {
        global $member, $CONF, $manager;
        // Only Super-Admins can do this
        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('createnewlog');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_addnewlog()
    {
        global $member, $manager, $CONF;
        // Only Super-Admins can do this
        $member->isAdmin() or $this->disallow();
        $bname          = trim(postVar('name'));
        $bshortname     = trim(postVar('shortname'));
        $btimeoffset    = postVar('timeoffset');
        $bdesc          = trim(postVar('desc'));
        $bdefskin       = postVar('defskin');

        if (!isValidShortName($bshortname)) {
            $this->error(_ERROR_BADSHORTBLOGNAME);
        }
        if ($manager->existsBlog($bshortname)) {
            $this->error(_ERROR_DUPSHORTBLOGNAME);
        }
        $manager->notify(
            'PreAddBlog',
            array(
                'name'        => &$bname,
                'shortname'   => &$bshortname,
                'timeoffset'  => &$btimeoffset,
                'description' => &$bdesc,
                'defaultskin' => &$bdefskin
            )
        );
        // create blog
        $query = 'INSERT '
               . 'INTO '
               .      sql_table('blog') . ' '
               . '('
               . '    bname, '
               . '    bshortname, '
               . '    bdesc, '
               . '    btimeoffset, '
               . '    bdefskin'
               . ') VALUES ('
               . '    "' . sql_real_escape_string($bname) . '", '
               . '    "' . sql_real_escape_string($bshortname) . '", '
               . '    "' . sql_real_escape_string($btimeoffset) . '", '
               . '    "' . sql_real_escape_string($bdesc) . '", '
               . '    "' . sql_real_escape_string($bdefskin) . '"'
               . ')';
        sql_query($query);
        $blogid = sql_insert_id();
        $blog   =& $manager->getBlog($blogid);
        // create new category
        $sql = 'INSERT INTO %s (cblog, cname, cdesc) VALUES (%d, "%s", "%s")';
        sql_query(sprintf($sql, sql_table('category'), $blogid, _EBLOGDEFAULTCATEGORY_NAME, _EBLOGDEFAULTCATEGORY_DESC));
        $catid = sql_insert_id();
        // set as default category
        $blog->setDefaultCategory($catid);
        $blog->writeSettings();
        // create team member
        $memberid = $member->getID();
        $query    = 'INSERT '
                  . 'INTO '
                  .      sql_table('team')
                  . '('
                  . '    tmember, '
                  . '    tblog, '
                  . '    tadmin'
                  . ') VALUES ('
                  .      intval($memberid) . ', '
                  .      intval($blogid) . ', '
                  . '    1'
                  . ')';
        sql_query($query);
        $blog->additem(
            $blog->getDefaultCategory(),
            _EBLOG_FIRSTITEM_TITLE,
            _EBLOG_FIRSTITEM_BODY,
            '',
            $blogid,
            $memberid,
            $blog->getCorrectTime(),
            0,
            0,
            0
        );
        $manager->notify(
            'PostAddBlog',
            array(
                'blog' => &$blog
            )
        );
        $manager->notify(
            'PostAddCategory',
            array(
                'blog'        => &$blog,
                'name'        => _EBLOGDEFAULTCATEGORY_NAME,
                'description' => _EBLOGDEFAULTCATEGORY_DESC,
                'catid'       => $catid
            )
        );
        $_REQUEST['blogid'] = $blogid;
        $_REQUEST['catid']  = $catid;
        $this->pagehead();
        $this->parse('addnewlog');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_addnewlog2()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $burl =  requestVar('url');
        $blog =& $manager->getBlog($blogid);
        $blog->setURL(trim($burl));
        $blog->writeSettings();
        $this->action_overview(_MSG_NEWBLOG);
    }

    /**
     * @todo document this
     */
    function action_skinieoverview()
    {
        global $member, $DIR_LIBS, $manager;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinie.php');
        $this->pagehead();
        $this->parse('skinieoverview');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_skinieimport()
    {
        global $member, $DIR_LIBS, $DIR_SKINS, $manager;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinie.php');
        $skinFileRaw= postVar('skinfile');
        $mode       = postVar('mode');
        $importer   = new SKINIMPORT();
        // get full filename
        if ($mode == 'file') {
            $skinFile = $DIR_SKINS . $skinFileRaw . '/skinbackup.xml';
            // backwards compatibilty (in v2.0, exports were saved as skindata.xml)
            if (!file_exists($skinFile)) {
                $skinFile = $DIR_SKINS . $skinFileRaw . '/skindata.xml';
            }
        } else {
            $skinFile = $skinFileRaw;
        }
        // read only metadata
        $error = $importer->readFile($skinFile, 1);
        if ($error) {
            $this->error($error);
        }

        $_REQUEST['skininfo']  = $importer->getInfo();
        $_REQUEST['skinnames'] = $importer->getSkinNames();
        $_REQUEST['tpltnames'] = $importer->getTemplateNames();

        // clashes
        $skinNameClashes         = $importer->checkSkinNameClashes();
        $templateNameClashes     = $importer->checkTemplateNameClashes();
        $hasNameClashes          = (count($skinNameClashes) > 0) || (count($templateNameClashes) > 0);
        $_REQUEST['skinclashes'] = $skinNameClashes;
        $_REQUEST['tpltclashes'] = $templateNameClashes;
        $_REQUEST['nameclashes'] = $hasNameClashes ? 1 : 0;

        $this->pagehead();
        $this->parse('skinieimport');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_skiniedoimport()
    {
        global $member, $DIR_LIBS, $DIR_SKINS;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinie.php');
        $skinFileRaw    = postVar('skinfile');
        $mode           = postVar('mode');
        $allowOverwrite = intPostVar('overwrite');
        // get full filename
        if ($mode == 'file') {
            $skinFile = $DIR_SKINS . $skinFileRaw . '/skinbackup.xml';
            // backwards compatibilty (in v2.0, exports were saved as skindata.xml)
            if (!file_exists($skinFile)) {
                $skinFile = $DIR_SKINS . $skinFileRaw . '/skindata.xml';
            }
        } else {
            $skinFile = $skinFileRaw;
        }
        $importer = new SKINIMPORT();
        $error    = $importer->readFile($skinFile);
        if ($error) {
            $this->error($error);
        }
        $error = $importer->writeToDatabase($allowOverwrite);
        if ($error) {
            $this->error($error);
        }

        $_REQUEST['skininfo']  = $importer->getInfo();
        $_REQUEST['skinnames'] = $importer->getSkinNames();
        $_REQUEST['tpltnames'] = $importer->getTemplateNames();

        $this->pagehead();
        $this->parse('skiniedoimport');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_skinieexport()
    {
        global $member, $DIR_LIBS;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinie.php');
        $aSkins     = requestIntArray('skin');
        $aTemplates = requestIntArray('template');
        if (!is_array($aTemplates)) {
            $aTemplates = array();
        }
        if (!is_array($aSkins)) {
            $aSkins = array();
        }
        $skinList     = array_keys($aSkins);
        $templateList = array_keys($aTemplates);

        $info = postVar('info');

        $exporter = new SKINEXPORT();
        foreach ($skinList as $skinId) {
            $exporter->addSkin($skinId);
        }
        foreach ($templateList as $templateId) {
            $exporter->addTemplate($templateId);
        }
        $exporter->setInfo($info);
        $exporter->export();
    }

    /**
     * @todo document this
     */
    function action_skinoverview() {
        global $member, $manager;

        $member->isAdmin() or $this->disallow();

        $this->pagehead();
        $this->parse('skinoverview');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_skinnew()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        $name = trim(postVar('name'));
        $desc = trim(postVar('desc'));

        if (!isValidSkinName($name)) {
            $this->error(_ERROR_BADSKINNAME);
        }
        if (SKIN::exists($name)) {
            $this->error(_ERROR_DUPSKINNAME);
        }
        $newId = SKIN::createNew($name, $desc);
        $this->action_skinoverview();
    }

    /**
     * @todo document this
     */
    function action_skinedit()
    {
        global $member, $manager;

        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('skinedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_skineditgeneral()
    {
        global $member;

        $skinid = intRequestVar('skinid');

        $member->isAdmin() or $this->disallow();

        $name       = postVar('name');
        $desc       = postVar('desc');
        $type       = postVar('type');
        $inc_mode   = postVar('inc_mode');
        $inc_prefix = postVar('inc_prefix');

        $skin = new SKIN($skinid);

        // 1. Some checks
        if (!isValidSkinName($name)) {
            $this->error(_ERROR_BADSKINNAME);
        }
        if (($skin->getName() != $name) && SKIN::exists($name)) {
            $this->error(_ERROR_DUPSKINNAME);
        }
        if (!$type) {
            $type = 'text/html';
        }
        if (!$inc_mode) {
            $inc_mode = 'normal';
        }
        // 2. Update description
        $skin->updateGeneralInfo($name, $desc, $type, $inc_mode, $inc_prefix);
        $this->action_skinedit();
    }

    /**
     * @todo document this
     */
    function action_skinedittype($msg = '')
    {
        global $member, $manager;

        $member->isAdmin() or $this->disallow();
        if ($msg) {
            $this->headMess = $msg;
        }
        $type = requestVar('type');
        $type = trim($type);
        $type = strtolower($type);
        if (!isValidShortName($type)) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_FORMAT);
        }
        $this->pagehead();
        $this->parse('skinedittype');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_skinupdate()
    {
        global $member;
        $skinid  = intRequestVar('skinid');
        $content = trim(postVar('content'));
        $type    = postVar('type');

        $member->isAdmin() or $this->disallow();

        $skin = new SKIN($skinid);
        $skin->update($type, $content);
        $this->action_skinedittype(_SKIN_UPDATED);
    }

    /**
     * @todo document this
     */
    function action_skindelete()
    {
        global $member, $manager, $CONF;
        $member->isAdmin() or $this->disallow();
        $skinid = intRequestVar('skinid');
        // don't allow default skin to be deleted
        if ($skinid == $CONF['BaseSkin']) {
            $this->error(_ERROR_DEFAULTSKIN);
        }
        // don't allow deletion of default skins for blogs
        $query = 'SELECT '
               . '    bname '
               . 'FROM '
               .      sql_table('blog') . ' '
               . 'WHERE '
               . '    bdefskin = ' . $skinid;
        $res   = sql_query($query);
        if ($o = sql_fetch_object($res)) {
            $this->error(_ERROR_SKINDEFDELETE . ENTITY::hsc($o->bname));
        }
        $this->pagehead();
        $this->parse('skindelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_skindeleteconfirm()
    {
        global $member, $CONF, $manager;
        $member->isAdmin() or $this->disallow();
        $skinid = intRequestVar('skinid');
        // don't allow default skin to be deleted
        if ($skinid == $CONF['BaseSkin']) {
            $this->error(_ERROR_DEFAULTSKIN);
        }
        // don't allow deletion of default skins for blogs
        $query = 'SELECT '
               . '    bname '
               . 'FROM '
               .      sql_table('blog') . ' '
               . 'WHERE '
               . '    bdefskin = ' . intval($skinid);
        $res   = sql_query($query);
        if ($o = sql_fetch_object($res)) {
            $this->error(_ERROR_SKINDEFDELETE .$o->bname);
        }
        $manager->notify(
            'PreDeleteSkin',
            array(
                'skinid' => intval($skinid)
            )
        );
        $query = 'DELETE FROM %s WHERE %s = ' . intval($skinid);
        // 1. delete description
        sql_query(sprintf($query, sql_table('skin_desc'), 'sdnumber'));
        // 2. delete parts
        sql_query(sprintf($query, sql_table('skin'), 'sdesc'));
        $manager->notify(
            'PostDeleteSkin',
            array(
                'skinid' => intval($skinid)
            )
        );
        $this->action_skinoverview();
    }

    /**
     * @todo document this
     */
    function action_skinremovetype()
    {
        global $member, $manager, $CONF;

        $member->isAdmin() or $this->disallow();
        $skinid   = intRequestVar('skinid');
        $skintype = requestVar('type');
        if (!isValidShortName($skintype)) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
        }
        // don't allow default skinparts to be deleted
        if (in_array($skintype, array('index', 'item', 'archivelist', 'archive', 'search', 'error', 'member', 'imagepopup'))) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
        }

        $this->pagehead();
        $this->parse('skinremovetype');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_skinremovetypeconfirm()
    {
        global $member, $CONF, $manager;

        $member->isAdmin() or $this->disallow();
        $skinid   = intRequestVar('skinid');
        $skintype = requestVar('type');
        if (!isValidShortName($skintype)) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
        }
        // don't allow default skinparts to be deleted
        if (in_array($skintype, array('index', 'item', 'archivelist', 'archive', 'search', 'error', 'member', 'imagepopup'))) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
        }
        $manager->notify(
            'PreDeleteSkinPart',
            array(
                'skinid'   => $skinid,
                'skintype' => $skintype
            )
        );
        // delete part
        $query = 'DELETE FROM %s WHERE sdesc = %d AND stype ="%s"';
        sql_query(sprintf($query, sql_table('skin'), intval($skinid), $skintype ));
        $manager->notify(
            'PostDeleteSkinPart',
            array(
                'skinid'   => $skinid,
                'skintype' => $skintype
            )
        );
        $this->action_skinedit();
    }

    /**
     * @todo document this
     */
    function action_skinclone()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        $skinid = intRequestVar('skinid');
        // 1. read skin to clone
        $skin = new SKIN($skinid);
        $name = "clone_" . $skin->getName();
        // if a skin with that name already exists:
        if (SKIN::exists($name)) {
            $i = 1;
            while (SKIN::exists($name . $i)) {
                $i++;
            }
            $name .= $i;
        }
        // 2. create skin desc
        $newid = SKIN::createNew(
            $name,
            $skin->getDescription(),
            $skin->getContentType(),
            $skin->getIncludeMode(),
            $skin->getIncludePrefix()
        );
        $query = 'SELECT '
               . '    stype '
               . 'FROM '
               .      sql_table('skin') . ' '
               . 'WHERE '
               . '    sdesc = ' . $skinid;
        $res   = sql_query($query);
        while ($row = sql_fetch_assoc($res)) {
            $this->skinclonetype($skin, $newid, $row['stype']);
        }
        $this->action_skinoverview();
    }

    /**
     * ADMIN::skinclonetype()
     * 
     * @param	String	$skin	Skin object
     * @param	Integer	$newid	ID for this clone
     * @param	String	$type	type of skin
     * @return	Void
     */
    function skinclonetype($skin, $newid, $type)
    {
        $newid   = intval($newid);
        $content = $skin->getContent($type);
        if ($content)
        {
            $query = "INSERT INTO %s (sdesc, scontent, stype) VALUES (%d, '%s', '%s')";
            $query = sprintf($query, sql_table('skin'), (integer) $newid, $content, $type);
            sql_query($query);
        }
        return;
    }

    /**
     * @todo document this
     */
    function action_adminskinoverview() {
        global $member, $manager;

        $member->isAdmin() or $this->disallow();

        $this->pagehead();
        $this->parse('adminskinoverview');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_adminskinnew()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        $name = trim(postVar('name'));
        $desc = trim(postVar('desc'));

        if (!isValidSkinName($name)) {
            $this->error(_ERROR_BADSKINNAME);
        }
        if (skinableSKIN::exists($name)) {
            $this->error(_ERROR_DUPSKINNAME);
        }
        $newId = skinableSKIN::createNew($name, $desc);
        $this->action_adminskinoverview();
    }

    /**
     * @todo document this
     */
    function action_adminskinedit()
    {
        global $member, $manager;

        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('adminskinedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_adminskineditgeneral()
    {
        global $member;

        $skinid = intRequestVar('skinid');

        $member->isAdmin() or $this->disallow();

        $name       = postVar('name');
        $desc       = postVar('desc');
        $type       = postVar('type');
        $inc_mode   = postVar('inc_mode');
        $inc_prefix = postVar('inc_prefix');

        $skin = new skinableSKIN($skinid);

        // 1. Some checks
        if (!isValidSkinName($name)) {
            $this->error(_ERROR_BADSKINNAME);
        }
        if (($skin->getName() != $name) && skinableSKIN::exists($name)) {
            $this->error(_ERROR_DUPSKINNAME);
        }
        if (!$type) {
            $type = 'text/html';
        }
        if (!$inc_mode) {
            $inc_mode = 'normal';
        }
        // 2. Update description
        $skin->updateGeneralInfo($name, $desc, $type, $inc_mode, $inc_prefix);
        $this->action_adminskinedit();
    }

    /**
     * @todo document this
     */
    function action_adminskinedittype($msg = '')
    {
        global $member, $manager;

        $member->isAdmin() or $this->disallow();
        if ($msg) {
            $this->headMess = $msg;
        }
        $type = requestVar('type');
        $type = trim($type);
        $type = strtolower($type);
        if (!isValidShortName($type)) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_FORMAT);
        }
        $this->pagehead();
        $this->parse('adminskinedittype');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_adminskinupdate()
    {
        global $member;
        $skinid  = intRequestVar('skinid');
        $content = trim(postVar('content'));
        $type    = postVar('type');

        $member->isAdmin() or $this->disallow();

        $skin = new skinableSKIN($skinid);
        $skin->update($type, $content);
        $this->action_adminskinedittype(_SKIN_UPDATED);
    }

    /**
     * @todo document this
     */
    function action_adminskindelete()
    {
        global $member, $manager, $CONF;
        $member->isAdmin() or $this->disallow();
        $skinid = intRequestVar('skinid');
        $this->pagehead();
        $this->parse('adminskindelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_adminskindeleteconfirm()
    {
        global $member, $CONF, $manager;
        $member->isAdmin() or $this->disallow();
        $skinid = intRequestVar('skinid');
        // don't allow default skin to be deleted
        if ($skinid == $CONF['DefaultAdminSkin']) {
            $this->error(_ERROR_DEFAULTSKIN);
        }
        // don't allow deletion of default skins for members
//        $skinableAdmin  = $manager->getPlugin('NP_SkinableAdmin');
//        $memberDefaults = $skinableAdmin->getAllMemberOptions('sknadmn_memid');
        $memberDefaults =  $member->getAdminSkin();
        foreach ($memberDefaults as $memID => $adminskin) {
            if ($skinid == $adminskin) {
                $mem = MEMBER::createFromID($memID);
                $this->error(_ERROR_SKINDEFDELETE . $mem->displayname);
            }
        }
        $manager->notify(
            'PreDeleteAdminSkin',
            array(
                'skinid' => intval($skinid)
            )
        );
        $query = 'DELETE FROM %s WHERE %s = ' . intval($skinid);
        // 1. delete description
        sql_query(sprintf($query, sql_table('adminskin_desc'), 'sdnumber'));
        // 2. delete parts
        sql_query(sprintf($query, sql_table('adminskin'), 'sdesc'));
        $manager->notify(
            'PostDeleteAdminSkin',
            array(
                'skinid' => intval($skinid)
            )
        );
        $this->action_adminskinoverview();
    }

    /**
     * @todo document this
     */
    function action_adminskinremovetype()
    {
        global $member, $manager, $CONF;

        $member->isAdmin() or $this->disallow();
        $skinid   = intRequestVar('skinid');
        $skintype = requestVar('type');
        if (!isValidShortName($skintype)) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
        }
        $this->pagehead();
        $this->parse('adminskinremovetype');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_adminskinremovetypeconfirm()
    {
        global $member, $CONF, $manager;

        $member->isAdmin() or $this->disallow();
        $skinid   = intRequestVar('skinid');
        $skintype = requestVar('type');
        if (!isValidShortName($skintype)) {
            $this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
        }
        $manager->notify(
            'PreDeleteAdminSkinPart',
            array(
                'skinid'   => $skinid,
                'skintype' => $skintype
            )
        );
        // delete part
        $query = 'DELETE FROM %s WHERE sdesc = %d AND stype ="%s"';
        sql_query(sprintf($query, sql_table('adminskin'), intval($skinid), $skintype ));
        $manager->notify(
            'PostDeleteAdminSkinPart',
            array(
                'skinid'   => $skinid,
                'skintype' => $skintype
            )
        );
        $this->action_adminskinedit();
    }

    /**
     * @todo document this
     */
    function action_adminskinclone()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        $skinid = intRequestVar('skinid');
        // 1. read skin to clone
        $skin = new skinableSKIN($skinid);
        $name = "clone_" . $skin->getName();
        // if a skin with that name already exists:
        if (skinableSKIN::exists($name)) {
            $i = 1;
            while (skinableSKIN::exists($name . $i)) {
                $i++;
            }
            $name .= $i;
        }
        // 2. create skin desc
        $newid = skinableSKIN::createNew(
            $name,
            $skin->getDescription(),
            $skin->getContentType(),
            $skin->getIncludeMode(),
            $skin->getIncludePrefix()
        );
        $query = 'SELECT '
               . '    stype '
               . 'FROM '
               .      sql_table('adminskin') . ' '
               . 'WHERE '
               . '    sdesc = ' . $skinid;
        $res   = sql_query($query);
        while ($row = sql_fetch_assoc($res)) {
            $this->adminskinclonetype($skin, $newid, $row['stype']);
        }
        $this->action_adminskinoverview();
    }

    /**
     * @todo document this
     */
    function adminskinclonetype($skin, $newid, $type)
    {
        $newid   = intval($newid);
        $content = $skin->getContent($type);
        if ($content) {
            $query = 'INSERT '
                   . 'INTO '
                   .      sql_table('adminskin') . ' '
                   . '('
                   . '    sdesc, '
                   . '    scontent, '
                   . '    stype'
                   . ') VALUES ('
                   .      intval($newid) . ', '
                   . '"' . sql_real_escape_string($content) . '", '
                   . '"' . sql_real_escape_string($type) . '" '
                   . ')';
            sql_query($query);
        }
    }

    /**
     * @todo document this
     */
    function action_adminskinieoverview()
    {
        global $member, $DIR_LIBS, $manager;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinableadmin/skinableSkinie.php');
        $this->pagehead();
        $this->parse('adminskinieoverview');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_adminskinieimport()
    {
        global $DIR_LIBS, $DIR_ADMINSKINS, $manager, $member;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinableadmin/skinableSkinie.php');
        $skinFileRaw= postVar('skinfile');
        $mode       = postVar('mode');
        $importer   = new skinableSKINIMPORT();
        // get full filename
        if ($mode == 'file') {
            $skinFile = $DIR_ADMINSKINS . $skinFileRaw . '/skinbackup.xml';
            // backwards compatibilty (in v2.0, exports were saved as skindata.xml)
            if (!file_exists($skinFile)) {
                $skinFile = $DIR_ADMINSKINS . $skinFileRaw . '/skindata.xml';
            }
        } else {
            $skinFile = $skinFileRaw;
        }
        // read only metadata
        $error = $importer->readFile($skinFile, 1);
        if ($error) {
            $this->error($error);
        }

        $_REQUEST['skininfo']  = $importer->getInfo();
        $_REQUEST['skinnames'] = $importer->getSkinNames();
        $_REQUEST['tpltnames'] = $importer->getTemplateNames();

        // clashes
        $skinNameClashes         = $importer->checkSkinNameClashes();
        $templateNameClashes     = $importer->checkTemplateNameClashes();
        $hasNameClashes          = (count($skinNameClashes) > 0) || (count($templateNameClashes) > 0);
        $_REQUEST['skinclashes'] = $skinNameClashes;
        $_REQUEST['tpltclashes'] = $templateNameClashes;
        $_REQUEST['nameclashes'] = $hasNameClashes ? 1 : 0;

        $this->pagehead();
        $this->parse('adminskinieimport');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_adminskiniedoimport()
    {
        global $DIR_LIBS, $DIR_ADMINSKINS, $member;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinableadmin/skinableSkinie.php');
        $skinFileRaw    = postVar('skinfile');
        $mode           = postVar('mode');
        $allowOverwrite = intPostVar('overwrite');
        // get full filename
        if ($mode == 'file') {
            $skinFile = $DIR_ADMINSKINS . $skinFileRaw . '/skinbackup.xml';
            // backwards compatibilty (in v2.0, exports were saved as skindata.xml)
            if (!file_exists($skinFile)) {
                $skinFile = $DIR_ADMINSKINS . $skinFileRaw . '/skindata.xml';
            }
        } else {
            $skinFile = $skinFileRaw;
        }
        $importer = new skinableSKINIMPORT();
        $error    = $importer->readFile($skinFile);
        if ($error) {
            $this->error($error);
        }
        $error = $importer->writeToDatabase($allowOverwrite);
        if ($error) {
            $this->error($error);
        }

        $_REQUEST['skininfo']  = $importer->getInfo();
        $_REQUEST['skinnames'] = $importer->getSkinNames();
        $_REQUEST['tpltnames'] = $importer->getTemplateNames();

        $this->pagehead();
        $this->parse('adminskiniedoimport');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_adminskinieexport()
    {
        global $member, $DIR_PLUGINS;
        $member->isAdmin() or $this->disallow();
        // load skinie class
//        include_once($DIR_PLUGINS . 'skinableadmin/core/skinableSkinie.php');
        $aSkins     = requestIntArray('skin');
        $aTemplates = requestIntArray('template');
        if (!is_array($aTemplates)) {
            $aTemplates = array();
        }
        if (!is_array($aSkins)) {
            $aSkins = array();
        }
        $skinList     = array_keys($aSkins);
        $templateList = array_keys($aTemplates);

        $info = postVar('info');

        $exporter = new skinableSKINEXPORT();
        foreach ($skinList as $skinId) {
            $exporter->addSkin($skinId);
        }
        foreach ($templateList as $templateId) {
            $exporter->addTemplate($templateId);
        }
        $exporter->setInfo($info);
        $exporter->export();
        
    }

    /**
     * @todo document this
     */
    function action_templateoverview()
    {
        global $member, $manager;
        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('templateoverview');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_templateedit($msg = '')
    {
        global $member, $manager;
        if ($msg) {
            $this->headMess = $msg;
        }
        $member->isAdmin() or $this->disallow();
        $extrahead  = '<script type="text/javascript" src="javascript/templateEdit.js"></script>' . "\n";
        $extrahead .= '<script type="text/javascript">setTemplateEditText("' . addslashes(_EDITTEMPLATE_EMPTY) . '");</script>';
        $this->pagehead($extrahead);
        $this->parse('templateedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_templateupdate()
    {
        global $member, $manager;
        $templateid = intRequestVar('templateid');
        $member->isAdmin() or $this->disallow();
        $name = postVar('tname');
        $desc = postVar('tdesc');

        if (!isValidTemplateName($name)) {
            $this->error(_ERROR_BADTEMPLATENAME);
        }
        if ((TEMPLATE::getNameFromId($templateid) != $name) && TEMPLATE::exists($name)) {
            $this->error(_ERROR_DUPTEMPLATENAME);
        }
//        $name = addslashes($name);
//        $desc = addslashes($desc);

        // 1. Remove all template parts
        $query = 'DELETE '
               . 'FROM '
               .      sql_table('template') . ' '
               . 'WHERE '
               . '    tdesc = %d';
        sql_query(sprintf($query, $templateid));

        // 2. Update description
        $query = 'UPDATE '
               .      sql_table('template_desc') . ' '
               . 'SET '
               . '    tdname = "' . sql_real_escape_string($name) . '", '
               . '    tddesc = "' . sql_real_escape_string($desc) . '" '
               . 'WHERE '
               . '    tdnumber = %d';
        sql_query(sprintf($query, $templateid));

        // 3. Add non-empty template parts
        $this->addToTemplate($templateid, 'ITEM_HEADER',                            postVar('ITEM_HEADER'));
        $this->addToTemplate($templateid, 'ITEM',                                   postVar('ITEM'));
        $this->addToTemplate($templateid, 'ITEM_FOOTER',                            postVar('ITEM_FOOTER'));
        $this->addToTemplate($templateid, 'MORELINK',                               postVar('MORELINK'));
        $this->addToTemplate($templateid, 'EDITLINK',                               postVar('EDITLINK'));
        $this->addToTemplate($templateid, 'NEW',                                    postVar('NEW'));
        $this->addToTemplate($templateid, 'COMMENTS_HEADER',                        postVar('COMMENTS_HEADER'));
        $this->addToTemplate($templateid, 'COMMENTS_BODY',                          postVar('COMMENTS_BODY'));
        $this->addToTemplate($templateid, 'COMMENTS_FOOTER',                        postVar('COMMENTS_FOOTER'));
        $this->addToTemplate($templateid, 'COMMENTS_CONTINUED',                     postVar('COMMENTS_CONTINUED'));
        $this->addToTemplate($templateid, 'COMMENTS_TOOMUCH',                       postVar('COMMENTS_TOOMUCH'));
        $this->addToTemplate($templateid, 'COMMENTS_AUTH',                          postVar('COMMENTS_AUTH'));
        $this->addToTemplate($templateid, 'COMMENTS_ONE',                           postVar('COMMENTS_ONE'));
        $this->addToTemplate($templateid, 'COMMENTS_MANY',                          postVar('COMMENTS_MANY'));
        $this->addToTemplate($templateid, 'COMMENTS_NONE',                          postVar('COMMENTS_NONE'));
        $this->addToTemplate($templateid, 'ARCHIVELIST_HEADER',                     postVar('ARCHIVELIST_HEADER'));
        $this->addToTemplate($templateid, 'ARCHIVELIST_LISTITEM',                   postVar('ARCHIVELIST_LISTITEM'));
        $this->addToTemplate($templateid, 'ARCHIVELIST_FOOTER',                     postVar('ARCHIVELIST_FOOTER'));
        $this->addToTemplate($templateid, 'BLOGLIST_HEADER',                        postVar('BLOGLIST_HEADER'));
        $this->addToTemplate($templateid, 'BLOGLIST_LISTITEM',                      postVar('BLOGLIST_LISTITEM'));
        $this->addToTemplate($templateid, 'BLOGLIST_FOOTER',                        postVar('BLOGLIST_FOOTER'));
        $this->addToTemplate($templateid, 'CATLIST_HEADER',                         postVar('CATLIST_HEADER'));
        $this->addToTemplate($templateid, 'CATLIST_LISTITEM',                       postVar('CATLIST_LISTITEM'));
        $this->addToTemplate($templateid, 'CATLIST_FOOTER',                         postVar('CATLIST_FOOTER'));
        $this->addToTemplate($templateid, 'DATE_HEADER',                            postVar('DATE_HEADER'));
        $this->addToTemplate($templateid, 'DATE_FOOTER',                            postVar('DATE_FOOTER'));
        $this->addToTemplate($templateid, 'FORMAT_DATE',                            postVar('FORMAT_DATE'));
        $this->addToTemplate($templateid, 'FORMAT_TIME',                            postVar('FORMAT_TIME'));
        $this->addToTemplate($templateid, 'LOCALE',                                 postVar('LOCALE'));
        $this->addToTemplate($templateid, 'SEARCH_HIGHLIGHT',                       postVar('SEARCH_HIGHLIGHT'));
        $this->addToTemplate($templateid, 'SEARCH_NOTHINGFOUND',                    postVar('SEARCH_NOTHINGFOUND'));
        $this->addToTemplate($templateid, 'POPUP_CODE',                             postVar('POPUP_CODE'));
        $this->addToTemplate($templateid, 'MEDIA_CODE',                             postVar('MEDIA_CODE'));
        $this->addToTemplate($templateid, 'IMAGE_CODE',                             postVar('IMAGE_CODE'));

        $pluginfields = array();
        $manager->notify(
            'TemplateExtraFields',
            array(
                'fields' => &$pluginfields
            )
        );
        foreach ($pluginfields as $pfkey => $pfvalue) {
            foreach ($pfvalue as $pffield => $pfdesc) {
                $this->addToTemplate($templateid, $pffield, postVar($pffield));
            }
        }

        // jump back to template edit
        $this->action_templateedit(_TEMPLATE_UPDATED);
    }

    /**
     * ADMIN::addToTemplate()
     * 
     * @param	Integer	$id	ID for template
     * @param	String	$partname	parts name
     * @param	String	$content	template contents
     * @return	Integer	record index
     * 
     */
    function addToTemplate($id, $partname, $content)
    {
        $partname = sql_real_escape_string($partname);
        $content = sql_real_escape_string($content);
        $id = intval($id);

        // don't add empty parts:
        if (!trim($content))
        {
            return -1;
        }

        $query = "INSERT INTO %s (tdesc, tpartname, tcontent) VALUES (%d, '%s', '%s')";
        $query = sprintf($query, sql_table('template'), (integer) $id, $partname, $content);
        sql_query($query) or exit(_ADMIN_SQLDIE_QUERYERROR . sql_error());
        return sql_insert_id();
    }

    /**
     * @todo document this
     */
    function action_templatedelete()
    {
        global $member, $manager;
        $member->isAdmin() or $this->disallow();
        // TODO: check if template can be deleted
        $this->pagehead();
        $this->parse('templatedelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_templatedeleteconfirm()
    {
        global $member, $manager;
        $templateid = intRequestVar('templateid');
        $member->isAdmin() or $this->disallow();
        $manager->notify(
            'PreDeleteTemplate',
            array(
                'templateid' => $templateid
            )
        );

        $query = 'DELETE '
               . 'FROM '
               . '    %s '
               . 'WHERE '
               . '    %s = ' .intval($templateid);
        // 1. delete description
        sql_query(sprintf($query, sql_table('template_desc'), 'tdnumber'));
        // 2. delete parts
        sql_query(sprintf($query, sql_table('template'), 'tdesc'));

        $manager->notify(
            'PostDeleteTemplate',
            array(
                'templateid' => $templateid
            )
        );
        $this->action_templateoverview();
    }

    /**
     * @todo document this
     */
    function action_templatenew()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        $name = postVar('name');
        $desc = postVar('desc');

        if (!isValidTemplateName($name)) {
            $this->error(_ERROR_BADTEMPLATENAME);
        }
        if (TEMPLATE::exists($name)) {
            $this->error(_ERROR_DUPTEMPLATENAME);
        }

        $newTemplateId = TEMPLATE::createNew($name, $desc);
        $this->action_templateoverview();
    }

    /**
     * @todo document this
     */
    function action_templateclone()
    {
        global $member;
        $templateid = intRequestVar('templateid');
        $member->isAdmin() or $this->disallow();

        // 1. read old template
        $name = TEMPLATE::getNameFromId($templateid);
        $desc = TEMPLATE::getDesc($templateid);
        // 2. create desc thing
        $name = "cloned" . $name;

        // if a template with that name already exists:
        if (TEMPLATE::exists($name)) {
            $i = 1;
            while (TEMPLATE::exists($name . $i)) {
                $i++;
            }
            $name .= $i;
        }

        $newid = TEMPLATE::createNew($name, $desc);

        // 3. create clone
        // go through parts of old template and add them to the new one
        $que = 'SELECT '
             . '    tpartname, '
             . '    tcontent '
             . 'FROM '
             .      sql_table('template') . ' '
             . 'WHERE '
             . '    tdesc = ' . intval($templateid);
        $res = sql_query($que);
        while ($o = sql_fetch_object($res)) {
            $this->addToTemplate($newid, $o->tpartname, $o->tcontent);
        }
        $this->action_templateoverview();
    }

    /**
     * @todo document this
     */
    function action_admintemplateoverview()
    {
        global $member, $manager;
        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('admintemplateoverview');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_admintemplateedit($msg = '')
    {
        global $member, $manager;
        if ($msg) {
            $this->headMess = $msg;
        }
        $member->isAdmin() or $this->disallow();
        $extrahead  = '<script type="text/javascript" src="javascript/templateEdit.js"></script>' . "\n";
        $extrahead .= '<script type="text/javascript">setTemplateEditText("' . sql_real_escape_string(_EDITTEMPLATE_EMPTY) . '");</script>';
        $this->pagehead($extrahead);
        $this->parse('admintemplateedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_admintemplateupdate()
    {
        global $member, $manager;
        $templateid = intRequestVar('templateid');
        $member->isAdmin() or $this->disallow();
        $name = postVar('tname');
        $desc = postVar('tdesc');

        if (!isValidTemplateName($name)) {
            $this->error(_ERROR_BADTEMPLATENAME);
        }
//        if (!class_exists('skinableTEMPLATE')) {
//            NP_SkinableAdmin::loadSkinableClass('skinableTEMPLATE');
//        }
        if ((skinableTEMPLATE::getNameFromId($templateid) != $name) && skinableTEMPLATE::exists($name)) {
            $this->error(_ERROR_DUPTEMPLATENAME);
        }
        $name = sql_real_escape_string($name);
        $desc = sql_real_escape_string($desc);

        // 1. Remove all template parts
        $query = 'DELETE '
               . 'FROM '
               .      sql_table('admintemplate') . ' '
               . 'WHERE '
               . '    tdesc = %d';
        sql_query(sprintf($query, $templateid));

        // 2. Update description
        $query = 'UPDATE '
               .      sql_table('admintemplate_desc') . ' '
               . 'SET '
               . '    tdname = "' . sql_real_escape_string($name) . '", '
               . '    tddesc = "' . sql_real_escape_string($desc) . '" '
               . 'WHERE '
               . '    tdnumber = %d';
        sql_query(sprintf($query, $templateid));

        // 3. Add non-empty template parts
        $this->addToAdminTemplate($templateid, 'ADMINSKINTYPELIST_HEAD',                 postVar('ADMINSKINTYPELIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'ADMINSKINTYPELIST_BODY',                 postVar('ADMINSKINTYPELIST_BODY'));
        $this->addToAdminTemplate($templateid, 'ADMINSKINTYPELIST_FOOT',                 postVar('ADMINSKINTYPELIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'ADMIN_CUSTOMHELPLINK_ICON',              postVar('ADMIN_CUSTOMHELPLINK_ICON'));
        $this->addToAdminTemplate($templateid, 'ADMIN_CUSTOMHELPLINK_ANCHOR',            postVar('ADMIN_CUSTOMHELPLINK_ANCHOR'));
        $this->addToAdminTemplate($templateid, 'ADMIN_BLOGLINK',                         postVar('ADMIN_BLOGLINK'));
        $this->addToAdminTemplate($templateid, 'ADMIN_BATCHLIST',                        postVar('ADMIN_BATCHLIST'));
        $this->addToAdminTemplate($templateid, 'ACTIVATE_FORGOT_TITLE',                  postVar('ACTIVATE_FORGOT_TITLE'));
        $this->addToAdminTemplate($templateid, 'ACTIVATE_FORGOT_TEXT',                   postVar('ACTIVATE_FORGOT_TEXT'));
        $this->addToAdminTemplate($templateid, 'ACTIVATE_REGISTER_TITLE',                postVar('ACTIVATE_REGISTER_TITLE'));
        $this->addToAdminTemplate($templateid, 'ACTIVATE_REGISTER_TEXT',                 postVar('ACTIVATE_REGISTER_TEXT'));
        $this->addToAdminTemplate($templateid, 'ACTIVATE_CHANGE_TITLE',                  postVar('ACTIVATE_CHANGE_TITLE'));
        $this->addToAdminTemplate($templateid, 'ACTIVATE_CHANGE_TEXT',                   postVar('ACTIVATE_CHANGE_TEXT'));
        $this->addToAdminTemplate($templateid, 'TEMPLATE_EDIT_EXPLUGNAME',               postVar('TEMPLATE_EDIT_EXPLUGNAME'));
        $this->addToAdminTemplate($templateid, 'TEMPLATE_EDIT_ROW_HEAD',                 postVar('TEMPLATE_EDIT_ROW_HEAD'));
        $this->addToAdminTemplate($templateid, 'TEMPLATE_EDIT_ROW_TAIL',                 postVar('TEMPLATE_EDIT_ROW_TAIL'));
        $this->addToAdminTemplate($templateid, 'SPECIALSKINLIST_HEAD',                   postVar('SPECIALSKINLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SPECIALSKINLIST_BODY',                   postVar('SPECIALSKINLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SPECIALSKINLIST_FOOT',                   postVar('SPECIALSKINLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SYSTEMINFO_GDSETTINGS',                  postVar('SYSTEMINFO_GDSETTINGS'));
        $this->addToAdminTemplate($templateid, 'BANLIST_DELETED_LIST',                   postVar('BANLIST_DELETED_LIST'));
        $this->addToAdminTemplate($templateid, 'INSERT_PLUGOPTION_TITLE',                postVar('INSERT_PLUGOPTION_TITLE'));
        $this->addToAdminTemplate($templateid, 'INSERT_PLUGOPTION_BODY',                 postVar('INSERT_PLUGOPTION_BODY'));
        $this->addToAdminTemplate($templateid, 'INPUTYESNO_TEMPLATE_ADMIN',              postVar('INPUTYESNO_TEMPLATE_ADMIN'));
        $this->addToAdminTemplate($templateid, 'INPUTYESNO_TEMPLATE_NORMAL',             postVar('INPUTYESNO_TEMPLATE_NORMAL'));
        $this->addToAdminTemplate($templateid, 'ADMIN_SPECIALSKINLIST_HEAD',             postVar('ADMIN_SPECIALSKINLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'ADMIN_SPECIALSKINLIST_BODY',             postVar('ADMIN_SPECIALSKINLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'ADMIN_SPECIALSKINLIST_FOOT',             postVar('ADMIN_SPECIALSKINLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SKINIE_EXPORT_LIST',                     postVar('SKINIE_EXPORT_LIST'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_SELECT_HEAD',          postVar('SHOWLIST_LISTPLUG_SELECT_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_SELECT_BODY',          postVar('SHOWLIST_LISTPLUG_SELECT_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_SELECT_FOOT',          postVar('SHOWLIST_LISTPLUG_SELECT_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_HEAD',           postVar('SHOWLIST_LISTPLUG_TABLE_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BODY',           postVar('SHOWLIST_LISTPLUG_TABLE_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_FOOT',           postVar('SHOWLIST_LISTPLUG_TABLE_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_MEMBLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_MEMBLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_MEMBLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_MEMBLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_MEMBLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_MEMBLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_TEAMLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_TEAMLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_TEAMLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_TEAMLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_TEAMLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_TEAMLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_GURL',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_GURL'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGEVENTLIST',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGEVENTLIST'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGNEDUPDATE',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGNEDUPDATE'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGIN_DEPEND',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGIN_DEPEND'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGIN_DEPREQ',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGIN_DEPREQ'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLISTFALSE',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLISTFALSE'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_ACTN',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_ACTN'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_ADMN',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_ADMN'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_HELP',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_HELP'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGOPTSETURL',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGOPTSETURL'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_POPTLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_POPTLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_POPTLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_POPTLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OYESNO',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OYESNO'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OPWORD',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OPWORD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OSELEP',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OSELEP'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OSELEO',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OSELEO'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OSELEC',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OSELEC'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OTAREA',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OTAREA'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLGOPT_OITEXT',  postVar('SHOWLIST_LISTPLUG_TABLE_PLGOPT_OITEXT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_PLUGOPTN_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_PLUGOPTN_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_POPTLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_POPTLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_ITEMLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_ITEMLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_ITEMLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_ITEMLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_ITEMLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_ITEMLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CMNTLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_CMNTLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CMNTLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_CMNTLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CMNTLIST_ABAN',  postVar('SHOWLIST_LISTPLUG_TABLE_CMNTLIST_ABAN'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CMNTLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_CMNTLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLOGLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_BLOGLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLOGLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_BLOGLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLIST_BD_TADM',  postVar('SHOWLIST_LISTPLUG_TABLE_BLIST_BD_TADM'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLIST_BD_SADM',  postVar('SHOWLIST_LISTPLUG_TABLE_BLIST_BD_SADM'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLOGLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_BLOGLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLOGSNAM_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_BLOGSNAM_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLOGSNAM_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_BLOGSNAM_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_BLOGSNAM_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_BLOGSNAM_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_SHORTNAM_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_SHORTNAM_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_SHORTNAM_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_SHORTNAM_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_SHORTNAM_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_SHORTNAM_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CATELIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_CATELIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CATELIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_CATELIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_CATELIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_CATELIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_TPLTLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_TPLTLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_TPLTLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_TPLTLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_TPLTLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_TPLTLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_SKINLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_SKINLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_SKINLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_SKINLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_SKINLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_SKINLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_DRFTLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_DRFTLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_DRFTLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_DRFTLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_DRFTLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_DRFTLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_ACTNLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_ACTNLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_ACTNLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_ACTNLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_ACTNLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_ACTNLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_IBANLIST_HEAD',  postVar('SHOWLIST_LISTPLUG_TABLE_IBANLIST_HEAD'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_IBANLIST_BODY',  postVar('SHOWLIST_LISTPLUG_TABLE_IBANLIST_BODY'));
        $this->addToAdminTemplate($templateid, 'SHOWLIST_LISTPLUG_TABLE_IBANLIST_FOOT',  postVar('SHOWLIST_LISTPLUG_TABLE_IBANLIST_FOOT'));
        $this->addToAdminTemplate($templateid, 'PLUGIN_QUICKMENU_TITLE',                 postVar('PLUGIN_QUICKMENU_TITLE'));
        $this->addToAdminTemplate($templateid, 'PLUGIN_QUICKMENU_HEAD',                  postVar('PLUGIN_QUICKMENU_HEAD'));
        $this->addToAdminTemplate($templateid, 'PLUGIN_QUICKMENU_BODY',                  postVar('PLUGIN_QUICKMENU_BODY'));
        $this->addToAdminTemplate($templateid, 'PLUGIN_QUICKMENU_FOOT',                  postVar('PLUGIN_QUICKMENU_FOOT'));

        $pluginfields = array();
        $manager->notify(
            'TemplateExtraFields',
            array(
                'fields' => &$pluginfields
            )
        );
        foreach ($pluginfields as $pfkey => $pfvalue) {
            foreach ($pfvalue as $pffield => $pfdesc) {
                $this->addToAdminTemplate($templateid, $pffield, postVar($pffield));
            }
        }

        // jump back to template edit
        $this->action_admintemplateedit(_TEMPLATE_UPDATED);
    }

    /**
     * @todo document this
     */
    function addToAdminTemplate($id, $partname, $content)
    {
        $partname = sql_real_escape_string($partname);
        $content  = sql_real_escape_string($content);


        $id = intval($id);

        // don't add empty parts:
        if (!trim($content)) {
            return -1;
        }
        $query = 'INSERT '
               . 'INTO '
               .      sql_table('admintemplate') . ' '
               . '('
               . '    tdesc, '
               . '    tpartname, '
               . '    tcontent '
               . ') VALUES ('
               . '    %d, '
               . '    "%s", '
               . '    "%s"'
               . ')';
        sql_query(sprintf($query, $id, $partname, $content)) or exit(_ADMIN_SQLDIE_QUERYERROR . sql_error());
        return sql_insert_id();
    }

    /**
     * @todo document this
     */
    function action_admintemplatedelete()
    {
        global $member, $manager;
        $member->isAdmin() or $this->disallow();
        // TODO: check if template can be deleted
        $this->pagehead();
        $this->parse('admintemplatedelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_admintemplatedeleteconfirm()
    {
        global $member, $manager;
        $templateid = intRequestVar('templateid');
        $member->isAdmin() or $this->disallow();
        $manager->notify(
            'PreDeleteAdminTemplate',
            array(
                'templateid' => $templateid
            )
        );

        $query = 'DELETE '
               . 'FROM '
               . '    %s '
               . 'WHERE '
               . '    %s = ' .intval($templateid);
        // 1. delete description
        sql_query(sprintf($query, sql_table('admintemplate_desc'), 'tdnumber'));
        // 2. delete parts
        sql_query(sprintf($query, sql_table('admintemplate'), 'tdesc'));

        $manager->notify(
            'PostDeleteAdminTemplate',
            array(
                'templateid' => $templateid
            )
        );
        $this->action_admintemplateoverview();
    }

    /**
     * @todo document this
     */
    function action_admintemplatenew()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        $name = postVar('name');
        $desc = postVar('desc');

        if (!isValidTemplateName($name)) {
            $this->error(_ERROR_BADTEMPLATENAME);
        }
//        if (!class_exists('skinableTEMPLATE')) {
//            NP_SkinableAdmin::loadSkinableClass('skinableTEMPLATE');
//        }
        if (skinableTEMPLATE::exists($name)) {
            $this->error(_ERROR_DUPTEMPLATENAME);
        }

        $newTemplateId = skinableTEMPLATE::createNew($name, $desc);
        $this->action_admintemplateoverview();
    }

    /**
     * @todo document this
     */
    function action_admintemplateclone()
    {
        global $member;
        $templateid = intRequestVar('templateid');
        $member->isAdmin() or $this->disallow();

//        if (!class_exists('skinableTEMPLATE')) {
//            NP_SkinableAdmin::loadSkinableClass('skinableTEMPLATE');
//        }

        // 1. read old template
        $name = skinableTEMPLATE::getNameFromId($templateid);
        $desc = skinableTEMPLATE::getDesc($templateid);
        // 2. create desc thing
        $name = "cloned" . $name;

        // if a template with that name already exists:
        if (skinableTEMPLATE::exists($name)) {
            $i = 1;
            while (skinableTEMPLATE::exists($name . $i)) {
                $i++;
            }
            $name .= $i;
        }

        $newid = skinableTEMPLATE::admincreateNew($name, $desc);

        // 3. create clone
        // go through parts of old template and add them to the new one
        $que = 'SELECT '
             . '    tpartname, '
             . '    tcontent '
             . 'FROM '
             .      sql_table('admintemplate') . ' '
             . 'WHERE '
             . '    tdesc = ' . intval($templateid);
        $res = sql_query($que);
        while ($o = sql_fetch_object($res)) {
            $this->addToAdminTemplate($newid, $o->tpartname, $o->tcontent);
        }
        $this->action_admintemplateoverview();
    }

    /**
     * ADMIN::action_settingsedit()
     * 
     * @param	Void
     * @return	Void
     */
    function action_settingsedit()
    {
        global $member, $manager, $CONF, $DIR_NUCLEUS, $DIR_MEDIA;

        $member->isAdmin() or $this->disallow();

        $this->pagehead();
        $this->parse('settingsedit');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_settingsupdate()
    {
        global $member, $CONF;
        $member->isAdmin() or $this->disallow();
        // check if email address for admin is valid
        if (!isValidMailAddress(postVar('AdminEmail'))) {
            $this->error(_ERROR_BADMAILADDRESS);
        }
//        var_dump($_POST);
        // save settings
        $this->updateConfig('DefaultBlog',      postVar('DefaultBlog'));
        $this->updateConfig('BaseSkin',         postVar('BaseSkin'));
        $this->updateConfig('IndexURL',         postVar('IndexURL'));
        $this->updateConfig('AdminURL',         postVar('AdminURL'));
        $this->updateConfig('PluginURL',        postVar('PluginURL'));
        $this->updateConfig('SkinsURL',         postVar('SkinsURL'));
        $this->updateConfig('ActionURL',        postVar('ActionURL'));
        $this->updateConfig('Locale',           postVar('Locale'));
        $this->updateConfig('AdminEmail',       postVar('AdminEmail'));
        $this->updateConfig('SessionCookie',    postVar('SessionCookie'));
        $this->updateConfig('AllowMemberCreate',postVar('AllowMemberCreate'));
        $this->updateConfig('AllowMemberMail',  postVar('AllowMemberMail'));
        $this->updateConfig('NonmemberMail',    postVar('NonmemberMail'));
        $this->updateConfig('ProtectMemNames',  postVar('ProtectMemNames'));
        $this->updateConfig('SiteName',         postVar('SiteName'));
        $this->updateConfig('NewMemberCanLogon',postVar('NewMemberCanLogon'));
        $this->updateConfig('DisableSite',      postVar('DisableSite'));
        $this->updateConfig('DisableSiteURL',   postVar('DisableSiteURL'));
        $this->updateConfig('LastVisit',        postVar('LastVisit'));
        $this->updateConfig('MediaURL',         postVar('MediaURL'));
        $this->updateConfig('AllowedTypes',     postVar('AllowedTypes'));
        $this->updateConfig('AllowUpload',      postVar('AllowUpload'));
        $this->updateConfig('MaxUploadSize',    postVar('MaxUploadSize'));
        $this->updateConfig('MediaPrefix',      postVar('MediaPrefix'));
        $this->updateConfig('AllowLoginEdit',   postVar('AllowLoginEdit'));
        $this->updateConfig('DisableJsTools',   postVar('DisableJsTools'));
        $this->updateConfig('CookieDomain',     postVar('CookieDomain'));
        $this->updateConfig('CookiePath',       postVar('CookiePath'));
        $this->updateConfig('CookieSecure',     postVar('CookieSecure'));
        $this->updateConfig('URLMode',          postVar('URLMode'));
        $this->updateConfig('CookiePrefix',     postVar('CookiePrefix'));
        $this->updateConfig('DebugVars',        postVar('DebugVars'));
        $this->updateConfig('DefaultListSize',  postVar('DefaultListSize'));
        $this->updateConfig('AdminCSS',         postVar('AdminCSS'));

        // load new config and redirect (this way, the new locale will be used is necessary)
        // note that when changing cookie settings, this redirect might cause the user
        // to have to log in again.
        getConfig();
        redirect($CONF['AdminURL'] . '?action=manage');
        exit;
    }

    /**
     *  Give an overview over the used system
     */
    function action_systemoverview()
    {
        $this->pagehead();
        $this->parse('systemoverview');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function updateConfig($name, $val)
    {
        $query = 'UPDATE '
               .      sql_table('config')
               . ' SET '
               . '    value = "' . trim(sql_real_escape_string($val)) . '" '
               . 'WHERE '
               . '    name  = "' . sql_real_escape_string($name) . '"';

        sql_query($query) or die(_ADMIN_SQLDIE_QUERYERROR . sql_error());
        return sql_insert_id();
    }

    /**
     * Error message
     * @param string $msg message that will be shown
     */
    function error($msg)
    {
        $this->headMess = $msg;
        $this->pagehead();
        $this->parse('adminerrorpage');
        $this->pagefoot();
        exit;
    }

    /**
     * @todo document this
     */
    function disallow()
    {
        ACTIONLOG::add(WARNING, _ACTIONLOG_DISALLOWED . serverVar('REQUEST_URI'));
        $this->error(_ERROR_DISALLOWED);
    }

    /**
     * @todo document this
     */
    function pagehead($extrahead = '')
    {
        if ($this->existsSkinContents('pagehead')) {
            if (isset($extrahead) && !empty($extrahead)) {
                $this->extrahead = $extrahead;
            }
            $this->parse('pagehead');
        } else {
            parent::pagehead($extrahead);
        }
    }

    /**
     * @todo document this
     */
    function pagefoot()
    {
        global $action, $member, $manager;

        if ($this->existsSkinContents('pagefoot')) {
            $manager->notify(
                'AdminPrePageFoot',
                array(
                    'action' => $this->action
                )
            );
            $this->parse('pagefoot');
            exit;
        } else {
            parent::pagefoot($extrahead);
        }
    }

    /**
     * @todo document this
     */
    function action_regfile()
    {
        global $member, $CONF;
        $blogid = intRequestVar('blogid');
        $member->teamRights($blogid) or $this->disallow();

        // header-code stolen from phpMyAdmin
        // REGEDIT and bookmarklet code stolen from GreyMatter
        $sjisBlogName = sprintf(_WINREGFILE_TEXT, getBlogNameFromID($blogid));
        $sjisBlogName = mb_convert_encoding($sjisBlogName, "SJIS", "auto");

        header('Content-Type: application/octetstream');
        header('Content-Disposition: filename="nucleus.reg"');
        header('Pragma: no-cache');
        header('Expires: 0');

        echo "REGEDIT4\n";
        echo "[HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\MenuExt\\" . $sjisBlogName . "]\n";
        echo '@="' . $CONF['AdminURL'] . "bookmarklet.php?action=contextmenucode&blogid=".intval($blogid)."\"\n";
        echo '"contexts"=hex:31';
    }

    /**
     * @todo document this
     */
    function action_bookmarklet()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        $member->teamRights($blogid) or $this->disallow();
        $this->pagehead();
        $this->parse('bookmarklet');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_actionlog()
    {
        global $member, $manager;
        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('actionlog');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_banlist()
    {
        global $member, $manager;
        $blogid = intRequestVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $this->pagehead();
        $this->parse('banlist');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_banlistdelete()
    {
        global $member;
        $blogid  = intRequestVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();
        $this->pagehead();
        $this->parse('banlistdelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_banlistdeleteconfirm()
    {
        global $member, $manager;

        $blogid = intPostVar('blogid');
        $member->blogAdminRights($blogid) or $this->disallow();

        $allblogs = postVar('allblogs');
        $iprange  = postVar('iprange');
        $deleted  = array();

        if (!$allblogs) {
            if (BAN::removeBan($blogid, $iprange)) {
                array_push($deleted, $blogid);
            }
        } else {
            // get blogs fot which member has admin rights
            $adminblogs = $member->getAdminBlogs();
            foreach ($adminblogs as $blogje) {
                if (BAN::removeBan($blogje, $iprange)) {
                    array_push($deleted, $blogje);
                }
            }
        }
        if (sizeof($deleted) == 0) {
            $this->error(_ERROR_DELETEBAN);
        }
        $_REQUEST['delblogs'] = $deleted;
        $this->pagehead();
        $this->parse('banlistdeleteconfirm');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_banlistnewfromitem()
    {
        $this->action_banlistnew(getBlogIDFromItemID(intRequestVar('itemid')));
    }

    /**
     * @todo document this
     */
    function action_banlistnew($blogid = '')
    {
        global $member, $manager;
        if ($blogid == '') {
            $blogid = intRequestVar('blogid');
        }
        $member->blogAdminRights($blogid) or $this->disallow();
        $_REQUEST['blogid'] = $blogid;

        $this->pagehead();
        $this->parse('banlistnew');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_banlistadd()
    {
        global $member;
        $blogid   = intPostVar('blogid');
        $allblogs = postVar('allblogs');
        $iprange  = postVar('iprange');
        if ($iprange == "custom") {
            $iprange = postVar('customiprange');
        }
        $reason  =  postVar('reason');
        $member->blogAdminRights($blogid) or $this->disallow();
        // TODO: check IP range validity

        if (!$allblogs) {
            if (!BAN::addBan($blogid, $iprange, $reason)) {
                $this->error(_ERROR_ADDBAN);
            }
        } else {
            // get blogs fot which member has admin rights
            $adminblogs = $member->getAdminBlogs();
            $failed     = 0;
            foreach ($adminblogs as $blogje) {
                if (!BAN::addBan($blogje, $iprange, $reason)) {
                    $failed = 1;
                }
            }
            if ($failed) {
                $this->error(_ERROR_ADDBAN);
            }
        }
        $this->action_banlist();
    }

    /**
     * @todo document this
     */
    function action_clearactionlog()
    {
        global $member;
        $member->isAdmin() or $this->disallow();
        ACTIONLOG::clear();
        $this->action_manage(_MSG_ACTIONLOGCLEARED);
    }

    /**
     * @todo document this
     */
    function action_backupoverview()
    {
        global $member, $manager;
        $member->isAdmin() or $this->disallow();

        $this->pagehead();
        $this->parse('backupoverview');
        $this->pagefoot();
    }

    /**
     * Backup::action_backupcreate()
     * create file for backup
     * 
     * @param   void
     * @return  void
     * 
     */
    function action_backupcreate()
    {
        global $member, $DIR_LIBS;
        $member->isAdmin() or $this->disallow();
        // use compression ?
        $useGzip = intval(postVar('gzip'));
        include($DIR_LIBS . 'backup.php');
        // try to extend time limit
        // (creating/restoring dumps might take a while)
        @set_time_limit(1200);
        $bu = new Backup();
        $bu->do_backup($useGzip);
        exit;
    }

    /**
	 * Backup::action_backuprestore()
	 * restoring from uploaded file
	 * 
	 * @param		void
	 * @return	void
     */
    function action_backuprestore()
    {
        global $member, $DIR_LIBS;
        $member->isAdmin() or $this->disallow();
        if (intPostVar('letsgo') != 1)
        {
            $this->error(_ERROR_BACKUP_NOTSURE);
        }
        include($DIR_LIBS . 'backup.php');
        // try to extend time limit
        // (creating/restoring dumps might take a while)
        @set_time_limit(1200);
        $bu      = new Backup();
        $message = $bu->do_restore();
        if ($message != '')
        {
            $this->error($message);
        }
        $this->pagehead();
        $this->parse('backuprestore');
        $this->pagefoot();

    }

    /**
     * @todo document this
     */
    function action_pluginlist()
    {
        global $member, $manager;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $this->pagehead();
        $this->parse('pluginlist');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_pluginhelp()
    {
        global $member, $manager, $DIR_PLUGINS, $CONF;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $plugid = intGetVar('plugid');
        if (!$manager->pidInstalled($plugid)) {
            $this->error(_ERROR_NOSUCHPLUGIN);
        }
        $this->pagehead();
        $this->parse('pluginhelp');
        $this->pagefoot();
    }

    /**
     * ADMIN::action_pluginadd()
     * 
     * @param	Void
     * @return	Void
     * 
     */
    function action_pluginadd()
    {
        global $member, $manager, $DIR_PLUGINS;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $name = postVar('filename');
        if ($manager->pluginInstalled($name)) {
            $this->error(_ERROR_DUPPLUGIN);
        }
        if (!checkPlugin($name)) {
            $this->error(_ERROR_PLUGFILEERROR . ' (' . ENTITY::hsc($name, ENT_QUOTES) . ')');
        }
        // get number of currently installed plugins
        $res        = sql_query('SELECT * FROM ' . sql_table('plugin'));
        $numCurrent = sql_num_rows($res);
        // plugin will be added as last one in the list
        $newOrder   = $numCurrent + 1;

        $manager->notify(
            'PreAddPlugin',
            array(
                'file' => &$name
            )
        );

        // do this before calling getPlugin (in case the plugin id is used there)
        $query = 'INSERT '
               . 'INTO '
               .      sql_table('plugin') . ' '
               . '('
               . '    porder, '
               . '    pfile'
               . ') VALUES ('
               .      $newOrder . ', '
               . '   "' . sql_real_escape_string($name) . '"'
               . ')';
        sql_query($query);
        $iPid  = sql_insert_id();
        $manager->clearCachedInfo('installedPlugins');
        // Load the plugin for condition checking and instalation
        $plugin =& $manager->getPlugin($name);
        // check if it got loaded (could have failed)
        if (!$plugin) {
            $query = 'DELETE '
                   . 'FROM '
                   .      sql_table('plugin') . ' '
                   . 'WHERE '
                   . '    pid = ' . intval($iPid);
            sql_query($query);
            $manager->clearCachedInfo('installedPlugins');
            $this->error(_ERROR_PLUGIN_LOAD);
        }
        // check if plugin needs a newer Nucleus version
        if (getNucleusVersion() < $plugin->getMinNucleusVersion()) {
            // uninstall plugin again...
            $this->deleteOnePlugin($plugin->getID());
            // ...and show error
            $this->error(_ERROR_NUCLEUSVERSIONREQ . ENTITY::hsc($plugin->getMinNucleusVersion(), ENT_QUOTES));
        }
        // check if plugin needs a newer Nucleus version
        if (getNucleusVersion() == $plugin->getMinNucleusVersion() && getNucleusPatchLevel() < $plugin->getMinNucleusPatchLevel()) {
            // uninstall plugin again...
            $this->deleteOnePlugin($plugin->getID());
            // ...and show error
            $nuc = $plugin->getMinNucleusVersion() . ' patch ' . $plugin->getMinNucleusPatchLevel();
            $msg = _ERROR_NUCLEUSVERSIONREQ . ENTITY::hsc($nuc, ENT_QUOTES);
            $this->error($msg);
        }
        $pluginList = $plugin->getPluginDep();
        $query      = 'SELECT '
                    . '    * '
                    . 'FROM '
                    .      sql_table('plugin') . ' '
                    . 'WHERE '
                    . '    pfile = "%s"';
        foreach ($pluginList as $pluginName) {
            $res = sql_query(sprintf($query, $pluginName));
            if (sql_num_rows($res) == 0) {
                // uninstall plugin again...
                $this->deleteOnePlugin($plugin->getID());
                $this->error(sprintf(_ERROR_INSREQPLUGIN, ENTITY::hsc($pluginName, ENT_QUOTES)));
            }
        }
        // call the install method of the plugin
        $plugin->install();

        $manager->notify(
            'PostAddPlugin',
            array(
                'plugin' => &$plugin
            )
        );

        // update all events
        $this->action_pluginupdate();
        return;
    }

    /**
     * ADMIN:action_pluginupdate():
     * 
     * @param	Void
     * @return	Void
     * 
     */
    function action_pluginupdate()
    {
        global $member, $manager, $CONF;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        // delete everything from plugin_events
        sql_query('DELETE FROM ' . sql_table('plugin_event'));
        // loop over all installed plugins
        $res = sql_query('SELECT pid, pfile FROM ' . sql_table('plugin'));
        while($o = sql_fetch_object($res)) {
            $pid  =  $o->pid;
            $plug =& $manager->getPlugin($o->pfile);
            if ($plug) {
                $eventList = $plug->getEventList();
                foreach ($eventList as $eventName) {
                    $query = "INSERT INTO %s (pid, event) VALUES (%d, '%s')";
                    $query = sprintf($query, sql_table('plugin_event'), (integer) $pid, sql_real_escape_string($eventName));
                    sql_query($query);
                }
            }
        }
        redirect($CONF['AdminURL'] . '?action=pluginlist');
        return;
    }

    /**
     * @todo document this
     */
    function action_plugindelete()
    {
        global $member, $manager;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $pid = intGetVar('plugid');
        if (!$manager->pidInstalled($pid)) {
            $this->error(_ERROR_NOSUCHPLUGIN);
        }
        $this->pagehead();
        $this->parse('plugindelete');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_plugindeleteconfirm()
    {
        global $member, $manager, $CONF;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $pid   = intPostVar('plugid');
        $error = $this->deleteOnePlugin($pid, 1);
        if ($error) {
            $this->error($error);
        }
        redirect($CONF['AdminURL'] . '?action=pluginlist');
//		$this->action_pluginlist();
    }

    /**
     * @todo document this
     */
    function deleteOnePlugin($pid, $callUninstall = 0)
    {
        global $manager;
        $pid = intval($pid);
        if (!$manager->pidInstalled($pid)) {
            return _ERROR_NOSUCHPLUGIN;
        }
        $que  = 'SELECT '
              . '    pfile as result '
              . 'FROM '
              .      sql_table('plugin') . ' '
              . 'WHERE '
              . '    pid = ' . $pid;
        $name = quickQuery($que);

        // check dependency before delete
        $que = 'SELECT '
             . '    pfile '
             . 'FROM '
             .      sql_table('plugin');
        $res = sql_query($que);
        while ($o = sql_fetch_object($res)) {
            $plug =& $manager->getPlugin($o->pfile);
            if ($plug) {
                $depList = $plug->getPluginDep();
                foreach ($depList as $depName) {
                    if ($name == $depName) {
                        return sprintf(_ERROR_DELREQPLUGIN, $o->pfile);
                    }
                }
            }
        }

        $manager->notify(
            'PreDeletePlugin',
            array(
                'plugid' => $pid
            )
        );

        // call the unInstall method of the plugin
        if ($callUninstall) {
            $plugin =& $manager->getPlugin($name);
            if ($plugin) {
                $plugin->unInstall();
            }
        }

        // delete all subscriptions
        $que = 'DELETE '
             . 'FROM '
             .      sql_table('plugin_event') . ' '
             . 'WHERE '
             . '    pid = ' . $pid;
        sql_query($que);

        // delete all options
        // get OIDs from plugin_option_desc
        $que   = 'SELECT '
               . '    oid '
               . 'FROM '
               .      sql_table('plugin_option_desc') . ' '
               . 'WHERE '
               . '    opid = ' . $pid;
        $res   = sql_query($que);
        $aOIDs = array();
        while ($o = sql_fetch_object($res)) {
            array_push($aOIDs, $o->oid);
        }

        // delete from plugin_option and plugin_option_desc
        $que = 'DELETE '
             . 'FROM '
             .      sql_table('plugin_option_desc') . ' '
             . 'WHERE '
             . '    opid = ' . $pid;
        sql_query($que);
        if (count($aOIDs) > 0) {
            sql_query('DELETE FROM '.sql_table('plugin_option').' WHERE oid in ('.implode(',',$aOIDs).')');
        }

        // update order numbers
        $que = 'SELECT '
             . '    porder '
             . 'FROM '
             .      sql_table('plugin') . ' '
             . 'WHERE '
             . '    pid = ' . $pid;
        $res = sql_query($que);
        $o   = sql_fetch_object($res);
        $que = 'UPDATE '
             .      sql_table('plugin') . ' '
             .'SET '
             . '    porder = (porder - 1) '
             . 'WHERE '
             . '    porder > ' . $o->porder;
        sql_query($que);

        // delete row
        $que = 'DELETE '
             . 'FROM '
             .      sql_table('plugin') . ' '
             . 'WHERE '
             . '    pid = ' . $pid;
        sql_query($que);

        $manager->clearCachedInfo('installedPlugins');
        $manager->notify(
            'PostDeletePlugin',
            array(
                'plugid' => $pid
            )
        );
        return '';
    }

    /**
     * @todo document this
     */
    function action_pluginup()
    {
        global $member, $manager, $CONF;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $plugid = intGetVar('plugid');
        if (!$manager->pidInstalled($plugid)) {
            $this->error(_ERROR_NOSUCHPLUGIN);
        }

        // 1. get old order number
        $que = 'SELECT '
             . '    porder '
             . 'FROM '
             .      sql_table('plugin') . ' '
             . 'WHERE '
             . '    pid = ' . $plugid;
        $res = sql_query($que);
        $o   = sql_fetch_object($res);
        $oldOrder = $o->porder;

        // 2. calculate new order number
        $newOrder = ($oldOrder > 1) ? ($oldOrder - 1) : 1;

        // 3. update plug numbers
        $que = 'UPDATE '
             .      sql_table('plugin') . ' '
             . 'SET '
             . '    porder = %d '
             . 'WHERE '
             . '    %s = %d';
        sql_query(sprintf($que, $oldOrder, 'porder', $newOrder));
        sql_query(sprintf($que, $newOrder, 'pid',    $plugid));

        //$this->action_pluginlist();
        // To avoid showing ticket in the URL, redirect to pluginlist, instead.
        redirect($CONF['AdminURL'] . '?action=pluginlist');
    }

    /**
     * @todo document this
     */
    function action_plugindown()
    {
        global $member, $manager, $CONF;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $plugid = intGetVar('plugid');
        if (!$manager->pidInstalled($plugid)) {
            $this->error(_ERROR_NOSUCHPLUGIN);
        }
        // 1. get old order number
        $que = 'SELECT '
             . '    porder '
             . 'FROM '
             .      sql_table('plugin') . ' '
             . 'WHERE '
             . '    pid = ' . $plugid;
        $res = sql_query($que);
        $o   = sql_fetch_object($res);
        $oldOrder = $o->porder;

        $res      = sql_query('SELECT * FROM '.sql_table('plugin'));
        $maxOrder = sql_num_rows($res);

        // 2. calculate new order number
        $newOrder = ($oldOrder < $maxOrder) ? ($oldOrder + 1) : $maxOrder;

        // 3. update plug numbers
        $que = 'UPDATE '
             .      sql_table('plugin') . ' '
             . 'SET '
             . '    porder = %d '
             . 'WHERE '
             . '    %s = %d';
        sql_query(sprintf($que, $oldOrder, 'porder', $newOrder));
        sql_query(sprintf($que, $newOrder, 'pid',    $plugid));

        //$this->action_pluginlist();
        // To avoid showing ticket in the URL, redirect to pluginlist, instead.
        redirect($CONF['AdminURL'] . '?action=pluginlist');
    }

    /**
     * @todo document this
     */
    function action_pluginoptions($message = '')
    {
        global $member, $manager;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $pid = intRequestVar('plugid');
        if (!$manager->pidInstalled($pid)) {
            $this->error(_ERROR_NOSUCHPLUGIN);
        }
        if ($message) {
            $this->headMess = $message;
        }
        $extrahead  = '<script type="text/javascript" src="javascript/numbercheck.js"></script>';
        $this->pagehead($extrahead);
        $this->parse('pluginoptions');
        $this->pagefoot();
    }

    /**
     * @todo document this
     */
    function action_pluginoptionsupdate()
    {
        global $member, $manager;
        // check if allowed
        $member->isAdmin() or $this->disallow();
        $pid = intRequestVar('plugid');
        if (!$manager->pidInstalled($pid)) {
            $this->error(_ERROR_NOSUCHPLUGIN);
        }

        $aOptions = requestArray('plugoption');
        NucleusPlugin::apply_plugin_options($aOptions);

        $manager->notify(
            'PostPluginOptionsUpdate',
            array(
                'context' => 'global',
                'plugid'  => $pid
            )
        );
        $this->action_pluginoptions(_PLUGS_OPTIONS_UPDATED);
    }

    /**
     * TODO: this document
     */
    function action_parseSpecialskin()
    {
        $this->pagehead();
        $this->parse($this->action);
        $this->pagefoot();
    }

    /**
     * @static
     * @todo document this
     */
    function _insertPluginOptions($context, $contextid = 0)
    {
        // get all current values for this contextid
        // (note: this might contain doubles for overlapping contextids)
        $aIdToValue = array();
        $query      = 'SELECT '
                    . '    oid, '
                    . '    ovalue '
                    . 'FROM '
                    .      sql_table('plugin_option') . ' '
                    . 'WHERE '
                    . '      ocontextid = %d';
        $resource   = sql_query(sprintf($query, intval($contextid)));
        while ($o = sql_fetch_object($resource)) {
            $aIdToValue[$o->oid] = $o->ovalue;
        }
        // get list of oids per pid
        $query    = 'SELECT '
                  . '    * '
                  . 'FROM '
                  .      sql_table('plugin_option_desc') . ', '
                  .      sql_table('plugin') . ' '
                  . 'WHERE '
                  . '    opid     = pid '
                  . 'and ocontext = "' . sql_real_escape_string($context) . '" '
                  . 'ORDER BY '
                  . '    porder, oid ASC';
        $res      = sql_query($query);
        $aOptions = array();
        while ($o = sql_fetch_object($res)) {
            if (in_array($o->oid, array_keys($aIdToValue))) {
                $value = $aIdToValue[$o->oid];
            } else {
                $value = $o->odef;
            }
            $aOptions[] = array(
                'pid'         => $o->pid,
                'pfile'       => $o->pfile,
                'oid'         => $o->oid,
                'value'       => $value,
                'name'        => $o->oname,
                'description' => $o->odesc,
                'type'        => $o->otype,
                'typeinfo'    => $o->oextra,
                'contextid'   => $contextid,
                'extra'       => ''
            );
        }

        global $manager;
        $manager->notify(
            'PrePluginOptionsEdit',
            array(
                'context'   => $context,
                'contextid' => $contextid,
                'options'   => &$aOptions
            )
        );

        $this->aOptions = $aOptions;
        $this->parse('insertpluginoptions');
    }

    function parse($type)
    {
        global $manager, $CONF;
        if ($type == 'pagehead') {
            $manager->notify(
                'InitAdminSkinParse',
                array(
                    'skin' => &$this->adminSkin,
                    'type' => $type
                )
            );
            // set output type
            sendContentType($this->adminSkin->getContentType(), 'skin', _CHARSET);
        }
        // set skin name as global var (so plugins can access it)
        global $currentSkinName;
        $currentSkinName = $this->adminSkin->getName();

        $contents = $this->adminSkin->getContent($type);

        if (!$contents) {
            // use base skin if this skin does not have contents
            $defskin  = new skinableSKIN($CONF['DefaultAdminSkin']);
            $contents = $defskin->getContent($type);
            if (!$contents) {
                echo _ERROR_SKIN;
                return;
            }
        }

        $actions = $this->adminSkin->getAllowedActionsForType($type);

        if ($type == 'pagehead') {
            $manager->notify(
                'PreAdminSkinParse',
                array(
                    'skin'     => &$this->adminSkin,
                    'type'     => $type,
                    'contents' => &$contents
                )
            );
        }

        // set IncludeMode properties of parser
        PARSER::setProperty('IncludeMode',$this->adminSkin->getIncludeMode());
        PARSER::setProperty('IncludePrefix',$this->adminSkin->getIncludePrefix());
        
        if ($type == 'createitem' || $type == 'itemedit') {
            $handler = new skinableFACTORY(intRequestVar('blogid'), $type, $this->adminSkin, $this);
            $actions = array_merge($actions, $handler->actions);
        } else {
            $handler = new skinableACTIONS($type, $this->adminSkin, $this);
            $actions = array_merge($actions, skinableACTIONS::getDefinedActions());
        }
        $parser = new PARSER($actions, $handler);
        $handler->setParser($parser);
        $handler->setSkin($this->adminSkin);
        $parser->parse($contents);

        if ($type == 'pagefoot') {
            $manager->notify(
                'PostAdminSkinParse',
                array(
                    'skin' => &$this->adminSkin,
                    'type' => $type,
                )
            );
        }
    }

    function getAdminskinIDFromName($skinname)
    {
        $query     = 'SELECT `sdnumber` as result FROM `%s` WHERE `sdname` = "%s"';
        $admnSknID = quickQuery(sprintf($query, sql_table('nucleus_adminskin_desc'), mysql_real_escape_string($skinname)));
        return intval($adminSkinID);
    }

    function getAdminskinNameFromID($skinid)
    {
        $query     = 'SELECT `sdname` as result FROM `%s` WHERE `sdnumber` = "%d"';
        $admnSknID = quickQuery(sprintf($query, sql_table('nucleus_adminskin_desc'), intval($skinid)));
        return intval($adminSkinID);
    }

    function action_importAdmin()
    {
        global $DIR_ADMINSKINS, $action;
        if ($action == 'adminskinieimport') {
            $this->_doAdminskinimport();
        }
        $skn                  = array();
        if ($action == 'showlogin') {
            $skinName = 'showlogin';
            $actnName = 'showlogin';
        } else {
            $skinName = 'defaultimporter';
            $actnName = 'importAdmin';
        }
        $contents             = file_get_contents($DIR_ADMINSKINS . $skinName . '.skn');
        $skn['id']            = 0;
        $skn['description']   = $skinName;
        $skn['contentType']   = 'importAdmin';
        $skn['includeMode']   = 'normal';
        $skn['includePrefix'] = '';
        $skn['name']          = 'defaultinporter';
        $this->adminSkin      = (object)$skn;
        $handler              = new skinableACTIONS($actnName, $this->adminSkin, $this);
        $actions              = skinableSKIN::getAllowedActionsForType($actnName);
        $parser = new PARSER($actions, $handler);
        $handler->setParser($parser);
        $handler->setSkin($this->adminSkin);
        $parser->parse($contents);
    }

    /**
     * @todo document this
     */
    private function _doAdminskinimport()
    {
        global $DIR_LIBS, $DIR_ADMINSKINS, $CONF, $member;
        $member->isAdmin() or $this->disallow();
        // load skinie class
        include_once($DIR_LIBS . 'skinableadmin/skinableSkinie.php');
        $skinFileRaw    = postVar('skinfile');
        $mode           = postVar('mode');
        $allowOverwrite = intPostVar('overwrite');
        // get full filename
        if ($mode == 'file') {
            $skinFile = $DIR_ADMINSKINS . $skinFileRaw . '/skinbackup.xml';
        } else {
            $skinFile = $skinFileRaw;
        }
        $importer = new skinableSKINIMPORT();
        $error    = $importer->readFile($skinFile);
        if ($error) {
            $this->error($error);
        }
        $error = $importer->writeToDatabase($allowOverwrite);
        if ($error) {
            $this->error($error);
        }

        $_REQUEST['skininfo']  = $importer->getInfo();
        $_REQUEST['skinnames'] = $importer->getSkinNames();
        $_REQUEST['tpltnames'] = $importer->getTemplateNames();

        header('Location: ' . $CONF['AdminURL']);
        exit;

    }

} // class ADMIN
